ngx-locatorjs 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ko.md +67 -39
- package/README.md +61 -24
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/node/cmp-scan.js +80 -56
- package/dist/node/config-setup.js +8 -4
- package/dist/node/file-opener.js +36 -10
- package/package.json +23 -28
package/README.ko.md
CHANGED
|
@@ -4,20 +4,24 @@
|
|
|
4
4
|
이 프로젝트는 [locatorjs.com](https://www.locatorjs.com/)에서 영감을 받았습니다.
|
|
5
5
|
|
|
6
6
|
**기능**
|
|
7
|
+
|
|
7
8
|
- Alt+클릭: 템플릿(.html) 열기
|
|
8
9
|
- Alt+Shift+클릭: 컴포넌트(.ts) 열기
|
|
9
10
|
- Alt 키 홀드: 컴포넌트 하이라이트 + 툴팁 표시
|
|
10
|
-
- Cursor, VS Code, WebStorm 지원
|
|
11
|
+
- Antigravity IDE, Cursor, Zed, VS Code, WebStorm 지원
|
|
11
12
|
|
|
12
13
|
**필수 단계 (1~4 반드시 수행)**
|
|
14
|
+
|
|
13
15
|
1. 패키지 설치: `npm i -D ngx-locatorjs`
|
|
14
16
|
2. 설정/프록시 생성: `npx locatorjs-config`
|
|
15
17
|
3. `main.ts`에 런타임 훅 추가 (아래 예시 참고)
|
|
16
|
-
4. 파일 오프너 서버 + dev 서버 실행 (둘 다 켜진 상태 유지): `npx locatorjs-open-in-editor --watch` + `ng serve --proxy-config
|
|
18
|
+
4. 파일 오프너 서버 + dev 서버 실행 (둘 다 켜진 상태 유지): `npx locatorjs-open-in-editor --watch` + `ng serve --proxy-config {proxyConfigPath}`
|
|
17
19
|
|
|
18
|
-
`npm run start` 사용 시 `--` 뒤에 전달: `npm run start -- --proxy-config
|
|
20
|
+
`npm run start` 사용 시 `--` 뒤에 전달: `npm run start -- --proxy-config {proxyConfigPath}`
|
|
21
|
+
`{proxyConfigPath}`는 `npx locatorjs-config`가 선택/병합한 실제 프록시 파일 경로로 바꿔서 사용하세요.
|
|
19
22
|
|
|
20
23
|
**Angular 코드 추가 (main.ts)**
|
|
24
|
+
|
|
21
25
|
```ts
|
|
22
26
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
23
27
|
import { AppModule } from './app/app.module';
|
|
@@ -33,9 +37,7 @@ platformBrowserDynamic()
|
|
|
33
37
|
.then(() => {
|
|
34
38
|
if (!environment.production) {
|
|
35
39
|
setTimeout(() => {
|
|
36
|
-
import('ngx-locatorjs').then((m) =>
|
|
37
|
-
m.installAngularLocator({ enableNetwork: true }),
|
|
38
|
-
);
|
|
40
|
+
import('ngx-locatorjs').then((m) => m.installAngularLocator({ enableNetwork: true }));
|
|
39
41
|
}, 1000);
|
|
40
42
|
}
|
|
41
43
|
})
|
|
@@ -43,6 +45,7 @@ platformBrowserDynamic()
|
|
|
43
45
|
```
|
|
44
46
|
|
|
45
47
|
**Angular 코드 추가 (standalone: bootstrapApplication)**
|
|
48
|
+
|
|
46
49
|
```ts
|
|
47
50
|
import { bootstrapApplication } from '@angular/platform-browser';
|
|
48
51
|
import { appConfig } from './app/app.config';
|
|
@@ -52,9 +55,7 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
52
55
|
.then(() => {
|
|
53
56
|
setTimeout(() => {
|
|
54
57
|
import('ngx-locatorjs')
|
|
55
|
-
.then((m) =>
|
|
56
|
-
m.installAngularLocator({ enableNetwork: true }),
|
|
57
|
-
)
|
|
58
|
+
.then((m) => m.installAngularLocator({ enableNetwork: true }))
|
|
58
59
|
.catch((err) => console.warn('[angular-locator] Failed to load:', err));
|
|
59
60
|
}, 1000);
|
|
60
61
|
})
|
|
@@ -62,56 +63,56 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
62
63
|
```
|
|
63
64
|
|
|
64
65
|
**Angular dev server 예시**
|
|
66
|
+
|
|
65
67
|
- CLI 실행
|
|
66
|
-
`ng serve --proxy-config
|
|
68
|
+
`ng serve --proxy-config {proxyConfigPath}`
|
|
67
69
|
|
|
68
70
|
- angular.json에 적용
|
|
69
|
-
`"serve"` 옵션에 `"proxyConfig": "
|
|
71
|
+
`"serve"` 옵션에 `"proxyConfig": "{proxyConfigPath}"` 추가
|
|
70
72
|
|
|
71
73
|
**컴포넌트 맵 스캔**
|
|
74
|
+
|
|
72
75
|
- 수동 스캔
|
|
73
|
-
`npx locatorjs-scan`
|
|
76
|
+
`npx locatorjs-scan`
|
|
74
77
|
|
|
75
78
|
- 변경 감지 자동 스캔(선택)
|
|
76
|
-
`nodemon --delay 2.5 -e ts,html -w src -w projects -w apps -w libs -x "npx locatorjs-scan"`
|
|
79
|
+
`nodemon --delay 2.5 -e ts,html -w src -w projects -w apps -w libs -x "npx locatorjs-scan"`
|
|
77
80
|
|
|
78
81
|
**가능한 것**
|
|
82
|
+
|
|
79
83
|
- Alt+클릭으로 템플릿 또는 컴포넌트 파일 열기 (개발 모드)
|
|
80
84
|
- Alt 키 홀드 시 컴포넌트 하이라이트 및 툴팁 표시
|
|
81
85
|
- 단일 Angular 앱, workspace, Nx 구조에서 동작
|
|
82
86
|
|
|
83
87
|
**불가능/제한 사항**
|
|
88
|
+
|
|
84
89
|
- SSR/SSG 환경에서는 동작하지 않음 (브라우저 DOM 기반)
|
|
85
90
|
|
|
86
91
|
**ngx-locatorjs.config.json 가이드**
|
|
87
92
|
파일 위치: 프로젝트 루트
|
|
88
93
|
|
|
89
94
|
**중요**
|
|
95
|
+
|
|
90
96
|
- `npx locatorjs-config`는 **실행한 현재 폴더를 기준**으로 설정합니다.
|
|
91
97
|
- 기본값: `port: 4123`, `workspaceRoot: "."`.
|
|
92
98
|
- 모노레포처럼 실제 Angular 앱이 하위 폴더에 있으면 `workspaceRoot`를 그 **상대 경로**로 수정하세요. (예: `apps/web`)
|
|
93
99
|
- `.gitignore`가 있으면 `npx locatorjs-config`가 `.open-in-editor/`를 자동 추가합니다. 커밋하려면 해당 항목을 제거하세요.
|
|
94
100
|
|
|
95
101
|
예시:
|
|
102
|
+
|
|
96
103
|
```json
|
|
97
104
|
{
|
|
98
|
-
"port": 4123,
|
|
99
|
-
"workspaceRoot": ".",
|
|
100
|
-
"editor": "cursor",
|
|
101
|
-
"fallbackEditor": "code",
|
|
105
|
+
"port": 4123,
|
|
106
|
+
"workspaceRoot": ".",
|
|
107
|
+
"editor": "cursor",
|
|
108
|
+
"fallbackEditor": "code",
|
|
102
109
|
"scan": {
|
|
103
|
-
/**
|
|
104
|
-
* 탐색할 컴포넌트의 경로 목록
|
|
105
|
-
*/
|
|
106
110
|
"includeGlobs": [
|
|
107
111
|
"src/**/*.{ts,tsx}",
|
|
108
112
|
"projects/**/*.{ts,tsx}",
|
|
109
113
|
"apps/**/*.{ts,tsx}",
|
|
110
114
|
"libs/**/*.{ts,tsx}"
|
|
111
115
|
],
|
|
112
|
-
/**
|
|
113
|
-
* 스캔에서 제외할 경로 목록
|
|
114
|
-
*/
|
|
115
116
|
"excludeGlobs": [
|
|
116
117
|
"**/node_modules/**",
|
|
117
118
|
"**/dist/**",
|
|
@@ -125,24 +126,40 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
125
126
|
}
|
|
126
127
|
```
|
|
127
128
|
|
|
129
|
+
**필드 설명**
|
|
130
|
+
|
|
131
|
+
- `port`: 로컬 file-opener 서버 포트입니다.
|
|
132
|
+
- `workspaceRoot`: 명령 실행 위치 기준 Angular 워크스페이스 루트 상대 경로입니다.
|
|
133
|
+
- `editor`: 기본 에디터입니다 (`cursor`, `zed`, `antigravity`, `code`, `webstorm`).
|
|
134
|
+
- `fallbackEditor`: 기본 에디터 실행 실패 시 사용할 대체 에디터입니다.
|
|
135
|
+
- `scan.includeGlobs`: 컴포넌트 소스 파일 탐색 대상 glob 목록입니다.
|
|
136
|
+
- `scan.excludeGlobs`: 컴포넌트 스캔에서 제외할 glob 목록입니다.
|
|
137
|
+
|
|
128
138
|
**프로젝트 구조별 includeGlobs 예시**
|
|
139
|
+
|
|
129
140
|
1. 일반 Angular 앱
|
|
130
|
-
`["src/app/**/*.ts"]`
|
|
141
|
+
`["src/app/**/*.ts"]`
|
|
131
142
|
2. Angular Workspace (projects/)
|
|
132
|
-
`["projects/**/*.{ts,tsx}"]`
|
|
143
|
+
`["projects/**/*.{ts,tsx}"]`
|
|
133
144
|
3. Nx (apps/libs)
|
|
134
|
-
`["apps/**/*.{ts,tsx}", "libs/**/*.{ts,tsx}"]`
|
|
145
|
+
`["apps/**/*.{ts,tsx}", "libs/**/*.{ts,tsx}"]`
|
|
135
146
|
|
|
136
147
|
**환경변수 우선순위**
|
|
148
|
+
|
|
137
149
|
1. `EDITOR_CMD` 예: `EDITOR_CMD="cursor --goto"`
|
|
138
150
|
2. `LAUNCH_EDITOR` 예: `LAUNCH_EDITOR=code`
|
|
139
151
|
3. `ngx-locatorjs.config.json`의 `editor`
|
|
140
152
|
4. 자동 감지된 에디터
|
|
141
153
|
|
|
142
|
-
**프록시 설정 (
|
|
143
|
-
`npx locatorjs-config` 실행 시
|
|
154
|
+
**프록시 설정 ({proxyConfigPath})**
|
|
155
|
+
`{proxyConfigPath}`는 `npx locatorjs-config` 실행 시 아래 규칙으로 결정됩니다.
|
|
156
|
+
|
|
157
|
+
- `angular.json`에 `proxyConfig`가 지정되어 있으면 그 파일에 병합합니다.
|
|
158
|
+
- 없고 `proxy.conf.json`이 있으면 그 파일에 병합합니다.
|
|
159
|
+
- 둘 다 없으면 `ngx-locatorjs.proxy.json`을 생성합니다.
|
|
144
160
|
|
|
145
161
|
예시:
|
|
162
|
+
|
|
146
163
|
```json
|
|
147
164
|
{
|
|
148
165
|
"/__open-in-editor": {
|
|
@@ -164,26 +181,28 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
164
181
|
```
|
|
165
182
|
|
|
166
183
|
**트러블슈팅**
|
|
184
|
+
|
|
167
185
|
1. CORS 에러
|
|
168
|
-
`ng serve --proxy-config
|
|
186
|
+
`ng serve --proxy-config {proxyConfigPath}` 사용 여부 확인
|
|
169
187
|
2. npm run 경고
|
|
170
|
-
`npm run start -- --proxy-config
|
|
188
|
+
`npm run start -- --proxy-config {proxyConfigPath}` 형태로 실행
|
|
171
189
|
3. 네트워크 비활성
|
|
172
|
-
`installAngularLocator({ enableNetwork: true })` 설정 확인
|
|
190
|
+
`installAngularLocator({ enableNetwork: true })` 설정 확인
|
|
173
191
|
4. component-map.json not found
|
|
174
|
-
`npx locatorjs-scan` 실행 후 `.open-in-editor/component-map.json` 생성 여부 확인
|
|
192
|
+
`npx locatorjs-scan` 실행 후 `.open-in-editor/component-map.json` 생성 여부 확인
|
|
175
193
|
5. 컴포넌트 변경이 반영되지 않음
|
|
176
|
-
`npx locatorjs-open-in-editor --watch` 사용 또는 `npx locatorjs-scan` 재실행
|
|
194
|
+
`npx locatorjs-open-in-editor --watch` 사용 또는 `npx locatorjs-scan` 재실행
|
|
177
195
|
6. 스캔 결과가 비어있거나 컴포넌트가 누락됨
|
|
178
|
-
`scan.includeGlobs` 경로 확인 후 재스캔. 실제 컴포넌트들이 위치한 경로를 입력해야 합니다.
|
|
196
|
+
`scan.includeGlobs` 경로 확인 후 재스캔. 실제 컴포넌트들이 위치한 경로를 입력해야 합니다.
|
|
179
197
|
7. 잘못된 파일이 열리거나 매칭이 안 됨
|
|
180
|
-
`workspaceRoot`가 Angular 앱 루트인지 확인
|
|
198
|
+
`workspaceRoot`가 Angular 앱 루트인지 확인
|
|
181
199
|
8. 하이라이트가 안 보이거나 info가 null로 나옴
|
|
182
|
-
`http://localhost:${port}/__cmp-map` 에서 컴포넌트 정보가 잘 나타나는지 확인
|
|
200
|
+
`http://localhost:${port}/__cmp-map` 에서 컴포넌트 정보가 잘 나타나는지 확인
|
|
183
201
|
9. 포트 충돌
|
|
184
|
-
`ngx-locatorjs.config.json`과 `
|
|
202
|
+
`ngx-locatorjs.config.json`과 `{proxyConfigPath}`에서 포트 일치 여부 확인
|
|
185
203
|
|
|
186
204
|
**주의**
|
|
205
|
+
|
|
187
206
|
- 개발 모드에서만 사용하세요. 프로덕션 번들에 포함되지 않도록 `environment.production` 체크를 권장합니다.
|
|
188
207
|
- 네트워크 요청은 opt-in이며 localhost로만 제한됩니다. `enableNetwork: true`로 활성화하세요.
|
|
189
208
|
|
|
@@ -191,6 +210,7 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
191
210
|
file-opener 서버와 Angular dev server를 한 번에 띄우려면 아래 방식 중 하나를 사용하세요.
|
|
192
211
|
|
|
193
212
|
### Option A: `concurrently`
|
|
213
|
+
|
|
194
214
|
```bash
|
|
195
215
|
npm i -D concurrently
|
|
196
216
|
```
|
|
@@ -198,12 +218,13 @@ npm i -D concurrently
|
|
|
198
218
|
```json
|
|
199
219
|
{
|
|
200
220
|
"scripts": {
|
|
201
|
-
"dev:locator": "concurrently -k -n opener,ng \"npx locatorjs-open-in-editor\" \"ng serve --proxy-config
|
|
221
|
+
"dev:locator": "concurrently -k -n opener,ng \"npx locatorjs-open-in-editor\" \"ng serve --proxy-config {proxyConfigPath}\""
|
|
202
222
|
}
|
|
203
223
|
}
|
|
204
224
|
```
|
|
205
225
|
|
|
206
226
|
### Option B: `npm-run-all`
|
|
227
|
+
|
|
207
228
|
```bash
|
|
208
229
|
npm i -D npm-run-all
|
|
209
230
|
```
|
|
@@ -212,8 +233,15 @@ npm i -D npm-run-all
|
|
|
212
233
|
{
|
|
213
234
|
"scripts": {
|
|
214
235
|
"locator:opener": "npx locatorjs-open-in-editor",
|
|
215
|
-
"dev:app": "ng serve --proxy-config
|
|
236
|
+
"dev:app": "ng serve --proxy-config {proxyConfigPath}",
|
|
216
237
|
"dev:locator": "run-p locator:opener dev:app"
|
|
217
238
|
}
|
|
218
239
|
}
|
|
219
240
|
```
|
|
241
|
+
|
|
242
|
+
** 고민 **
|
|
243
|
+
|
|
244
|
+
처음 세팅할 때 귀찮은 단계가 많다고 느낍니다.
|
|
245
|
+
설치하고, `npx locatorjs-config`를 돌리고, `main.ts`에 훅을 넣고, opener와 dev server를 proxy 설정과 함께 실행..
|
|
246
|
+
|
|
247
|
+
이 흐름을 더 짧고 자연스럽게 만들고 싶습니다. 의견은 언제나 환영합니다.
|
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
한국어 문서: [README.ko.md](README.ko.md)
|
|
6
6
|
|
|
7
7
|
Open Angular component files directly from the browser with **Alt + Click** during development. This package provides:
|
|
8
|
+
|
|
8
9
|
- Browser runtime for Alt+click / hover UI
|
|
9
10
|
- CLI tools to scan Angular components and open files in your editor
|
|
10
11
|
- Config + proxy setup guidance
|
|
@@ -12,29 +13,34 @@ Open Angular component files directly from the browser with **Alt + Click** duri
|
|
|
12
13
|
Inspired by [locatorjs.com](https://www.locatorjs.com/).
|
|
13
14
|
|
|
14
15
|
## Features
|
|
16
|
+
|
|
15
17
|
- **Alt + Click**: open template (.html)
|
|
16
18
|
- **Alt + Shift + Click**: open component (.ts)
|
|
17
19
|
- **Hold Alt**: highlight component + tooltip
|
|
18
|
-
- Supports **Cursor**, **VS Code**, **WebStorm**
|
|
20
|
+
- Supports **Antigravity IDE**, **Cursor**, **Zed**, **VS Code**, **WebStorm**
|
|
19
21
|
|
|
20
22
|
## Install
|
|
23
|
+
|
|
21
24
|
```bash
|
|
22
25
|
npm i -D ngx-locatorjs
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
## Required Steps (Do This First)
|
|
29
|
+
|
|
26
30
|
You must complete steps 1–4 for this to work.
|
|
27
31
|
|
|
28
32
|
1. Install the package: `npm i -D ngx-locatorjs`
|
|
29
33
|
2. Generate config + proxy: `npx locatorjs-config`
|
|
30
34
|
3. Add the runtime hook to `main.ts` (see the examples below)
|
|
31
|
-
4. Run the file-opener server and your dev server (keep both running): `npx locatorjs-open-in-editor --watch` + `ng serve --proxy-config
|
|
35
|
+
4. Run the file-opener server and your dev server (keep both running): `npx locatorjs-open-in-editor --watch` + `ng serve --proxy-config {proxyConfigPath}`
|
|
32
36
|
|
|
33
|
-
If you use `npm run start`, pass args after `--`: `npm run start -- --proxy-config
|
|
37
|
+
If you use `npm run start`, pass args after `--`: `npm run start -- --proxy-config {proxyConfigPath}`
|
|
38
|
+
Replace `{proxyConfigPath}` with the actual proxy file path selected/updated by `npx locatorjs-config`.
|
|
34
39
|
|
|
35
40
|
## Add to `main.ts`
|
|
36
41
|
|
|
37
42
|
### NgModule bootstrap
|
|
43
|
+
|
|
38
44
|
```ts
|
|
39
45
|
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|
40
46
|
import { AppModule } from './app/app.module';
|
|
@@ -51,8 +57,8 @@ platformBrowserDynamic()
|
|
|
51
57
|
if (!environment.production) {
|
|
52
58
|
setTimeout(() => {
|
|
53
59
|
import('ngx-locatorjs')
|
|
54
|
-
.then(
|
|
55
|
-
m.installAngularLocator({ enableNetwork: true }), // required for network access (localhost-only)
|
|
60
|
+
.then(
|
|
61
|
+
(m) => m.installAngularLocator({ enableNetwork: true }), // required for network access (localhost-only)
|
|
56
62
|
)
|
|
57
63
|
.catch((err) => console.warn('[angular-locator] Failed to load:', err));
|
|
58
64
|
}, 1000);
|
|
@@ -62,6 +68,7 @@ platformBrowserDynamic()
|
|
|
62
68
|
```
|
|
63
69
|
|
|
64
70
|
### Standalone bootstrap
|
|
71
|
+
|
|
65
72
|
```ts
|
|
66
73
|
import { bootstrapApplication } from '@angular/platform-browser';
|
|
67
74
|
import { appConfig } from './app/app.config';
|
|
@@ -71,8 +78,8 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
71
78
|
.then(() => {
|
|
72
79
|
setTimeout(() => {
|
|
73
80
|
import('ngx-locatorjs')
|
|
74
|
-
.then(
|
|
75
|
-
m.installAngularLocator({ enableNetwork: true }), // required for network access (localhost-only)
|
|
81
|
+
.then(
|
|
82
|
+
(m) => m.installAngularLocator({ enableNetwork: true }), // required for network access (localhost-only)
|
|
76
83
|
)
|
|
77
84
|
.catch((err) => console.warn('[angular-locator] Failed to load:', err));
|
|
78
85
|
}, 1000);
|
|
@@ -81,34 +88,31 @@ bootstrapApplication(AppComponent, appConfig)
|
|
|
81
88
|
```
|
|
82
89
|
|
|
83
90
|
## Config Guide (`ngx-locatorjs.config.json`)
|
|
91
|
+
|
|
84
92
|
Location: project root
|
|
85
93
|
|
|
86
94
|
**Important**
|
|
95
|
+
|
|
87
96
|
- `npx locatorjs-config` uses the **current directory** as the base.
|
|
88
97
|
- Defaults: `port: 4123`, `workspaceRoot: "."`.
|
|
89
98
|
- In a monorepo, update `workspaceRoot` to the **relative path** of your Angular app (e.g. `apps/web`).
|
|
90
99
|
- If `.gitignore` exists, `npx locatorjs-config` will append `.open-in-editor/`. Remove it if you want to commit the map.
|
|
91
100
|
|
|
92
101
|
Example:
|
|
102
|
+
|
|
93
103
|
```json
|
|
94
104
|
{
|
|
95
|
-
"port": 4123,
|
|
96
|
-
"workspaceRoot": ".",
|
|
97
|
-
"editor": "cursor",
|
|
98
|
-
"fallbackEditor": "code",
|
|
105
|
+
"port": 4123,
|
|
106
|
+
"workspaceRoot": ".",
|
|
107
|
+
"editor": "cursor",
|
|
108
|
+
"fallbackEditor": "code",
|
|
99
109
|
"scan": {
|
|
100
|
-
/**
|
|
101
|
-
* Globs to include when scanning components
|
|
102
|
-
*/
|
|
103
110
|
"includeGlobs": [
|
|
104
111
|
"src/**/*.{ts,tsx}",
|
|
105
112
|
"projects/**/*.{ts,tsx}",
|
|
106
113
|
"apps/**/*.{ts,tsx}",
|
|
107
114
|
"libs/**/*.{ts,tsx}"
|
|
108
115
|
],
|
|
109
|
-
/**
|
|
110
|
-
* Globs to exclude from scanning
|
|
111
|
-
*/
|
|
112
116
|
"excludeGlobs": [
|
|
113
117
|
"**/node_modules/**",
|
|
114
118
|
"**/dist/**",
|
|
@@ -122,15 +126,31 @@ Example:
|
|
|
122
126
|
}
|
|
123
127
|
```
|
|
124
128
|
|
|
129
|
+
### Field Reference
|
|
130
|
+
|
|
131
|
+
- `port`: Port for the local file-opener server.
|
|
132
|
+
- `workspaceRoot`: Angular workspace root path (relative to where you run commands).
|
|
133
|
+
- `editor`: Preferred editor (`cursor`, `zed`, `antigravity`, `code`, `webstorm`).
|
|
134
|
+
- `fallbackEditor`: Fallback editor if the preferred editor cannot be launched.
|
|
135
|
+
- `scan.includeGlobs`: Globs used to find component source files.
|
|
136
|
+
- `scan.excludeGlobs`: Globs excluded from component scanning.
|
|
137
|
+
|
|
125
138
|
### Example includeGlobs
|
|
139
|
+
|
|
126
140
|
- Simple app: `"src/app/**/*.ts"`
|
|
127
141
|
- Angular workspace: `"projects/**/*.{ts,tsx}"`
|
|
128
142
|
- Nx: `"apps/**/*.{ts,tsx}", "libs/**/*.{ts,tsx}"`
|
|
129
143
|
|
|
130
|
-
## Proxy (`
|
|
131
|
-
|
|
144
|
+
## Proxy (`{proxyConfigPath}`)
|
|
145
|
+
|
|
146
|
+
`{proxyConfigPath}` is decided by `npx locatorjs-config`:
|
|
147
|
+
|
|
148
|
+
- If `angular.json` already specifies `proxyConfig`, it updates that file.
|
|
149
|
+
- Else if `proxy.conf.json` exists, it updates that file.
|
|
150
|
+
- Otherwise it creates `ngx-locatorjs.proxy.json`.
|
|
132
151
|
|
|
133
152
|
Example:
|
|
153
|
+
|
|
134
154
|
```json
|
|
135
155
|
{
|
|
136
156
|
"/__open-in-editor": {
|
|
@@ -152,30 +172,35 @@ Example:
|
|
|
152
172
|
```
|
|
153
173
|
|
|
154
174
|
## Environment Variable Priority
|
|
175
|
+
|
|
155
176
|
1. `EDITOR_CMD` (example: `cursor --goto`)
|
|
156
177
|
2. `LAUNCH_EDITOR` (example: `code`)
|
|
157
178
|
3. `ngx-locatorjs.config.json` → `editor`
|
|
158
179
|
4. auto-detected editor
|
|
159
180
|
|
|
160
181
|
## Troubleshooting
|
|
161
|
-
|
|
162
|
-
- **
|
|
182
|
+
|
|
183
|
+
- **CORS / JSON parse error**: ensure dev server uses `--proxy-config {proxyConfigPath}`
|
|
184
|
+
- **npm run shows "Unknown cli config --proxy-config"**: use `npm run start -- --proxy-config {proxyConfigPath}`
|
|
163
185
|
- **Network disabled**: pass `enableNetwork: true` to `installAngularLocator`
|
|
164
186
|
- **component-map.json not found**: run `npx locatorjs-scan`
|
|
165
187
|
- **Component changes not reflected**: run `npx locatorjs-open-in-editor --watch` or re-run `npx locatorjs-scan`
|
|
166
188
|
- **Map is empty or missing components**: check `scan.includeGlobs` and rerun the scan
|
|
167
189
|
- **Wrong files open or nothing matches**: confirm `workspaceRoot` points to the actual Angular app root
|
|
168
190
|
- **No highlight / info is null**: make sure `http://localhost:${port}/__cmp-map` is loading and includes your component class name
|
|
169
|
-
- **Port conflict**: change port in both `ngx-locatorjs.config.json` and `
|
|
191
|
+
- **Port conflict**: change port in both `ngx-locatorjs.config.json` and `{proxyConfigPath}`
|
|
170
192
|
|
|
171
193
|
## Notes
|
|
194
|
+
|
|
172
195
|
- Use only in development (guard with `environment.production`).
|
|
173
196
|
- Network requests are opt-in and limited to localhost. Set `enableNetwork: true` to activate.
|
|
174
197
|
|
|
175
198
|
## One-Command Dev (Recommended)
|
|
199
|
+
|
|
176
200
|
Running the file-opener server and Angular dev server separately is tedious. You can wire them into a single script.
|
|
177
201
|
|
|
178
202
|
### Option A: `concurrently`
|
|
203
|
+
|
|
179
204
|
```bash
|
|
180
205
|
npm i -D concurrently
|
|
181
206
|
```
|
|
@@ -183,12 +208,13 @@ npm i -D concurrently
|
|
|
183
208
|
```json
|
|
184
209
|
{
|
|
185
210
|
"scripts": {
|
|
186
|
-
"dev:locator": "concurrently -k -n opener,ng \"npx locatorjs-open-in-editor\" \"ng serve --proxy-config
|
|
211
|
+
"dev:locator": "concurrently -k -n opener,ng \"npx locatorjs-open-in-editor\" \"ng serve --proxy-config {proxyConfigPath}\""
|
|
187
212
|
}
|
|
188
213
|
}
|
|
189
214
|
```
|
|
190
215
|
|
|
191
216
|
### Option B: `npm-run-all`
|
|
217
|
+
|
|
192
218
|
```bash
|
|
193
219
|
npm i -D npm-run-all
|
|
194
220
|
```
|
|
@@ -197,16 +223,27 @@ npm i -D npm-run-all
|
|
|
197
223
|
{
|
|
198
224
|
"scripts": {
|
|
199
225
|
"locator:opener": "npx locatorjs-open-in-editor",
|
|
200
|
-
"dev:app": "ng serve --proxy-config
|
|
226
|
+
"dev:app": "ng serve --proxy-config {proxyConfigPath}",
|
|
201
227
|
"dev:locator": "run-p locator:opener dev:app"
|
|
202
228
|
}
|
|
203
229
|
}
|
|
204
230
|
```
|
|
205
231
|
|
|
206
232
|
## What It Can Do
|
|
233
|
+
|
|
207
234
|
- Open template or component files with Alt+click in development
|
|
208
235
|
- Show component highlight and tooltip while holding Alt
|
|
209
236
|
- Works with single apps, Angular workspace, and Nx layouts
|
|
210
237
|
|
|
211
238
|
## Limitations
|
|
239
|
+
|
|
212
240
|
- Not supported in SSR/SSG runtime (browser DOM only)
|
|
241
|
+
|
|
242
|
+
## Maintainer Note (Setup UX)
|
|
243
|
+
|
|
244
|
+
Current setup works, but the first-time flow still feels too manual. You install, run
|
|
245
|
+
`npx locatorjs-config`, add the bootstrap hook in `main.ts`, and then run opener + dev server
|
|
246
|
+
with proxy config.
|
|
247
|
+
|
|
248
|
+
This is an area we want to keep improving. Contributions that reduce setup friction are welcome,
|
|
249
|
+
especially around safer automation, clearer defaults, and better error guidance.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,MAAM,GAAG;IACZ,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAChD,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/browser/index.ts"],"names":[],"mappings":"AAAA,KAAK,OAAO,GAAG;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,KAAK,MAAM,GAAG;IACZ,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CAChD,CAAC;AAkBF,MAAM,MAAM,uBAAuB,GAAG;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,SAAS,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC7C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AA4EF,iBAAe,SAAS,CAAC,YAAY,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CA2B9D;AA+eD,wBAAsB,qBAAqB,CAAC,OAAO,GAAE,qBAA0B,iBAa9E;AAED,wBAAsB,mBAAmB,kBASxC;AAED,wBAAsB,mBAAmB,kBAExC;AAED,wBAAgB,yBAAyB,YAExC;AAED,eAAO,MAAM,SAAS;;CAErB,CAAC"}
|
package/dist/node/cmp-scan.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import ts from 'typescript';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import { glob } from 'glob';
|
|
5
6
|
const DEFAULT_INCLUDE_GLOBS = [
|
|
6
7
|
'src/**/*.{ts,tsx}',
|
|
7
8
|
'projects/**/*.{ts,tsx}',
|
|
@@ -31,28 +32,71 @@ function readConfig() {
|
|
|
31
32
|
function toPosix(p) {
|
|
32
33
|
return p.replace(/\\/g, '/');
|
|
33
34
|
}
|
|
34
|
-
function prefixWorkspaceRoot(
|
|
35
|
+
function prefixWorkspaceRoot(globPattern, workspaceRoot) {
|
|
35
36
|
if (!workspaceRoot || workspaceRoot === '.' || workspaceRoot === './')
|
|
36
|
-
return
|
|
37
|
-
if (path.isAbsolute(
|
|
38
|
-
return
|
|
37
|
+
return globPattern;
|
|
38
|
+
if (path.isAbsolute(globPattern))
|
|
39
|
+
return globPattern;
|
|
39
40
|
const rootPosix = toPosix(workspaceRoot).replace(/\/+$/, '');
|
|
40
|
-
const globPosix = toPosix(
|
|
41
|
+
const globPosix = toPosix(globPattern).replace(/^\/+/, '');
|
|
41
42
|
if (globPosix.startsWith(rootPosix + '/'))
|
|
42
43
|
return globPosix;
|
|
43
44
|
return `${rootPosix}/${globPosix}`;
|
|
44
45
|
}
|
|
45
|
-
function
|
|
46
|
-
|
|
46
|
+
function extractTemplateUrl(node) {
|
|
47
|
+
for (const prop of node.properties) {
|
|
48
|
+
if (ts.isPropertyAssignment(prop) &&
|
|
49
|
+
ts.isIdentifier(prop.name) &&
|
|
50
|
+
prop.name.text === 'templateUrl') {
|
|
51
|
+
const initializer = prop.initializer;
|
|
52
|
+
if (ts.isStringLiteral(initializer)) {
|
|
53
|
+
return initializer.text;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
function findComponentDecorator(node) {
|
|
60
|
+
if (!node.modifiers)
|
|
61
|
+
return undefined;
|
|
62
|
+
for (const modifier of node.modifiers) {
|
|
63
|
+
if (ts.isDecorator(modifier)) {
|
|
64
|
+
const expr = modifier.expression;
|
|
65
|
+
if (ts.isCallExpression(expr) && ts.isIdentifier(expr.expression)) {
|
|
66
|
+
if (expr.expression.text === 'Component') {
|
|
67
|
+
return modifier;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return undefined;
|
|
47
73
|
}
|
|
48
|
-
function
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
function parseSourceFile(filePath, sourceCode) {
|
|
75
|
+
const sourceFile = ts.createSourceFile(filePath, sourceCode, ts.ScriptTarget.Latest, true);
|
|
76
|
+
const components = [];
|
|
77
|
+
function visit(node) {
|
|
78
|
+
if (ts.isClassDeclaration(node) && node.name) {
|
|
79
|
+
const componentDecorator = findComponentDecorator(node);
|
|
80
|
+
if (componentDecorator) {
|
|
81
|
+
const expr = componentDecorator.expression;
|
|
82
|
+
const firstArg = expr.arguments[0];
|
|
83
|
+
if (firstArg && ts.isObjectLiteralExpression(firstArg)) {
|
|
84
|
+
const templateUrl = extractTemplateUrl(firstArg);
|
|
85
|
+
const className = node.name.text;
|
|
86
|
+
const absTs = path.resolve(root, filePath);
|
|
87
|
+
const absTpl = templateUrl ? path.resolve(path.dirname(absTs), templateUrl) : undefined;
|
|
88
|
+
components.push({
|
|
89
|
+
className,
|
|
90
|
+
filePath: absTs,
|
|
91
|
+
templateUrl: absTpl,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
ts.forEachChild(node, visit);
|
|
97
|
+
}
|
|
98
|
+
visit(sourceFile);
|
|
99
|
+
return components;
|
|
56
100
|
}
|
|
57
101
|
async function main() {
|
|
58
102
|
const cfg = readConfig();
|
|
@@ -88,14 +132,16 @@ async function main() {
|
|
|
88
132
|
}
|
|
89
133
|
return stats;
|
|
90
134
|
}
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
135
|
+
const allFiles = [];
|
|
136
|
+
for (const pattern of effectiveIncludeGlobs) {
|
|
137
|
+
const files = await glob(pattern, {
|
|
138
|
+
ignore: excludeGlobs,
|
|
139
|
+
absolute: true,
|
|
140
|
+
cwd: root,
|
|
141
|
+
});
|
|
142
|
+
allFiles.push(...files);
|
|
143
|
+
}
|
|
144
|
+
const filePaths = [...new Set(allFiles)];
|
|
99
145
|
const currentStats = getFileStats(filePaths);
|
|
100
146
|
const previousCache = loadCache();
|
|
101
147
|
const hasChanges = filePaths.some((filePath) => !previousCache[filePath] || previousCache[filePath] !== currentStats[filePath]);
|
|
@@ -108,38 +154,16 @@ async function main() {
|
|
|
108
154
|
}
|
|
109
155
|
const detailByFilePath = {};
|
|
110
156
|
const filePathsByClassName = {};
|
|
111
|
-
for (const
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
for (const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
continue;
|
|
122
|
-
const obj = arg.asKindOrThrow(SyntaxKind.ObjectLiteralExpression);
|
|
123
|
-
const templateUrlProp = obj.getProperty('templateUrl');
|
|
124
|
-
const templateUrl = templateUrlProp
|
|
125
|
-
?.asKind(SyntaxKind.PropertyAssignment)
|
|
126
|
-
?.getInitializer()
|
|
127
|
-
?.getText()
|
|
128
|
-
.replace(/^`|^'|^"|"|'|`$/g, '');
|
|
129
|
-
const className = cls.getName();
|
|
130
|
-
if (!className)
|
|
131
|
-
continue;
|
|
132
|
-
const absTs = path.resolve(root, filePath);
|
|
133
|
-
const absTpl = templateUrl ? path.resolve(path.dirname(absTs), templateUrl) : undefined;
|
|
134
|
-
detailByFilePath[absTs] = {
|
|
135
|
-
className,
|
|
136
|
-
filePath: absTs,
|
|
137
|
-
templateUrl: absTpl,
|
|
138
|
-
};
|
|
139
|
-
if (!filePathsByClassName[className])
|
|
140
|
-
filePathsByClassName[className] = [];
|
|
141
|
-
if (!filePathsByClassName[className].includes(absTs)) {
|
|
142
|
-
filePathsByClassName[className].push(absTs);
|
|
157
|
+
for (const filePath of filePaths) {
|
|
158
|
+
const sourceCode = fs.readFileSync(filePath, 'utf8');
|
|
159
|
+
const components = parseSourceFile(filePath, sourceCode);
|
|
160
|
+
for (const cmp of components) {
|
|
161
|
+
detailByFilePath[cmp.filePath] = cmp;
|
|
162
|
+
if (!filePathsByClassName[cmp.className]) {
|
|
163
|
+
filePathsByClassName[cmp.className] = [];
|
|
164
|
+
}
|
|
165
|
+
if (!filePathsByClassName[cmp.className].includes(cmp.filePath)) {
|
|
166
|
+
filePathsByClassName[cmp.className].push(cmp.filePath);
|
|
143
167
|
}
|
|
144
168
|
}
|
|
145
169
|
}
|
|
@@ -94,7 +94,8 @@ async function startSetup() {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
catch (error) {
|
|
97
|
-
|
|
97
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
98
|
+
console.error('\n❌ Setup failed:', message);
|
|
98
99
|
process.exit(1);
|
|
99
100
|
}
|
|
100
101
|
}
|
|
@@ -156,7 +157,7 @@ function findProxyConfigFromAngularJson() {
|
|
|
156
157
|
const angularJson = JSON.parse(fs.readFileSync(angularJsonPath, 'utf8'));
|
|
157
158
|
const projects = angularJson?.projects ?? {};
|
|
158
159
|
for (const project of Object.values(projects)) {
|
|
159
|
-
const targets = project
|
|
160
|
+
const targets = project.architect || project.targets;
|
|
160
161
|
const serve = targets?.serve;
|
|
161
162
|
if (!serve)
|
|
162
163
|
continue;
|
|
@@ -202,6 +203,8 @@ function logDefaults() {
|
|
|
202
203
|
function selectEditor() {
|
|
203
204
|
const availableEditors = [
|
|
204
205
|
{ name: 'Cursor', value: 'cursor' },
|
|
206
|
+
{ name: 'Zed', value: 'zed' },
|
|
207
|
+
{ name: 'Antigravity IDE', value: 'antigravity' },
|
|
205
208
|
{ name: 'VS Code', value: 'code' },
|
|
206
209
|
{ name: 'WebStorm', value: 'webstorm' },
|
|
207
210
|
];
|
|
@@ -215,7 +218,7 @@ function selectEditor() {
|
|
|
215
218
|
output: process.stdout,
|
|
216
219
|
});
|
|
217
220
|
return new Promise((resolve) => {
|
|
218
|
-
rl.question('\nEnter number (1-
|
|
221
|
+
rl.question('\nEnter number (1-5, default: 1 for Cursor): ', (answer) => {
|
|
219
222
|
rl.close();
|
|
220
223
|
const choice = parseInt(answer.trim(), 10) || 1;
|
|
221
224
|
const selected = availableEditors[Math.max(0, Math.min(choice - 1, availableEditors.length - 1))];
|
|
@@ -253,7 +256,7 @@ function selectEditor() {
|
|
|
253
256
|
renderMenu();
|
|
254
257
|
break;
|
|
255
258
|
case '\r':
|
|
256
|
-
case '\n':
|
|
259
|
+
case '\n': {
|
|
257
260
|
process.stdin.setRawMode(false);
|
|
258
261
|
process.stdin.pause();
|
|
259
262
|
process.stdin.removeListener('data', handleKeypress);
|
|
@@ -261,6 +264,7 @@ function selectEditor() {
|
|
|
261
264
|
console.log(`\n✨ Selected: ${selected.name}`);
|
|
262
265
|
resolve(selected.value);
|
|
263
266
|
break;
|
|
267
|
+
}
|
|
264
268
|
case '\u0003':
|
|
265
269
|
console.log('\n\nCancelled. Setting Cursor as default.');
|
|
266
270
|
process.stdin.setRawMode(false);
|
package/dist/node/file-opener.js
CHANGED
|
@@ -16,6 +16,9 @@ if (!fs.existsSync(configPath)) {
|
|
|
16
16
|
console.log('Or manually create the config file.');
|
|
17
17
|
process.exit(1);
|
|
18
18
|
}
|
|
19
|
+
function isErrnoException(error) {
|
|
20
|
+
return typeof error === 'object' && error !== null && 'code' in error;
|
|
21
|
+
}
|
|
19
22
|
const DEFAULT_INCLUDE_GLOBS = [
|
|
20
23
|
'src/**/*.{ts,tsx}',
|
|
21
24
|
'projects/**/*.{ts,tsx}',
|
|
@@ -46,12 +49,14 @@ function checkEditorCLI(editorName, cliCommand = editorName) {
|
|
|
46
49
|
return editorCLICache[editorName];
|
|
47
50
|
}
|
|
48
51
|
const MAC_APP_NAMES = {
|
|
52
|
+
antigravity: 'Antigravity IDE',
|
|
49
53
|
cursor: 'Cursor',
|
|
50
54
|
code: 'Visual Studio Code',
|
|
55
|
+
zed: 'Zed',
|
|
51
56
|
webstorm: 'WebStorm',
|
|
52
57
|
};
|
|
53
58
|
function detectAvailableEditors() {
|
|
54
|
-
const editors = ['cursor', 'code', 'webstorm'];
|
|
59
|
+
const editors = ['cursor', 'zed', 'antigravity', 'code', 'webstorm'];
|
|
55
60
|
const available = [];
|
|
56
61
|
for (const editor of editors) {
|
|
57
62
|
if (checkEditorCLI(editor)) {
|
|
@@ -61,9 +66,18 @@ function detectAvailableEditors() {
|
|
|
61
66
|
return available;
|
|
62
67
|
}
|
|
63
68
|
const AVAILABLE_EDITORS = detectAvailableEditors();
|
|
64
|
-
const DEFAULT_EDITOR = process.env.LAUNCH_EDITOR || cfg.editor ||
|
|
65
|
-
const FALLBACK_EDITOR = cfg.fallbackEditor ||
|
|
69
|
+
const DEFAULT_EDITOR = process.env.LAUNCH_EDITOR || cfg.editor || 'cursor';
|
|
70
|
+
const FALLBACK_EDITOR = cfg.fallbackEditor ||
|
|
71
|
+
AVAILABLE_EDITORS.find((editor) => editor.name !== DEFAULT_EDITOR)?.name ||
|
|
72
|
+
'code';
|
|
66
73
|
const COMMAND_TEMPLATES = {
|
|
74
|
+
antigravity: (file) => {
|
|
75
|
+
if (checkEditorCLI('antigravity')) {
|
|
76
|
+
return ['antigravity', ['--goto', file]];
|
|
77
|
+
}
|
|
78
|
+
const filePath = file.split(':')[0];
|
|
79
|
+
return ['open', ['-a', MAC_APP_NAMES.antigravity, filePath]];
|
|
80
|
+
},
|
|
67
81
|
cursor: (file) => {
|
|
68
82
|
if (checkEditorCLI('cursor')) {
|
|
69
83
|
return ['cursor', ['--goto', file]];
|
|
@@ -78,6 +92,13 @@ const COMMAND_TEMPLATES = {
|
|
|
78
92
|
const filePath = file.split(':')[0];
|
|
79
93
|
return ['open', ['-a', MAC_APP_NAMES.code, filePath]];
|
|
80
94
|
},
|
|
95
|
+
zed: (file) => {
|
|
96
|
+
if (checkEditorCLI('zed')) {
|
|
97
|
+
return ['zed', [file]];
|
|
98
|
+
}
|
|
99
|
+
const filePath = file.split(':')[0];
|
|
100
|
+
return ['open', ['-a', MAC_APP_NAMES.zed, filePath]];
|
|
101
|
+
},
|
|
81
102
|
webstorm: (file) => {
|
|
82
103
|
if (checkEditorCLI('webstorm')) {
|
|
83
104
|
const [filePath, line, col] = file.split(':');
|
|
@@ -100,7 +121,8 @@ function launchInEditor(fileWithPos, preferred = DEFAULT_EDITOR) {
|
|
|
100
121
|
return true;
|
|
101
122
|
}
|
|
102
123
|
catch (e) {
|
|
103
|
-
|
|
124
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
125
|
+
console.log(`[file-opener] EDITOR_CMD failed: ${message}`);
|
|
104
126
|
}
|
|
105
127
|
}
|
|
106
128
|
const tryRun = (editor) => {
|
|
@@ -113,7 +135,8 @@ function launchInEditor(fileWithPos, preferred = DEFAULT_EDITOR) {
|
|
|
113
135
|
return true;
|
|
114
136
|
}
|
|
115
137
|
catch (e) {
|
|
116
|
-
|
|
138
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
139
|
+
console.log(`[file-opener] ${editor} failed: ${message}`);
|
|
117
140
|
return false;
|
|
118
141
|
}
|
|
119
142
|
};
|
|
@@ -155,7 +178,8 @@ function findBestLineInFile(filePath, searchTerms) {
|
|
|
155
178
|
return bestScore > 0 ? bestLine : 1;
|
|
156
179
|
}
|
|
157
180
|
catch (e) {
|
|
158
|
-
|
|
181
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
182
|
+
console.warn(`[file-opener] Failed to search in file: ${message}`);
|
|
159
183
|
return 1;
|
|
160
184
|
}
|
|
161
185
|
}
|
|
@@ -215,7 +239,8 @@ function startScanWatch() {
|
|
|
215
239
|
watchers.push(watcher);
|
|
216
240
|
}
|
|
217
241
|
catch (err) {
|
|
218
|
-
|
|
242
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
243
|
+
console.log(`[file-opener] failed to watch ${watchPath}: ${message}`);
|
|
219
244
|
throw err;
|
|
220
245
|
}
|
|
221
246
|
};
|
|
@@ -321,9 +346,10 @@ const server = http.createServer((req, res) => {
|
|
|
321
346
|
res.end(`Opened at line ${bestLine}`);
|
|
322
347
|
}
|
|
323
348
|
catch (e) {
|
|
324
|
-
|
|
349
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
350
|
+
console.warn(`[file-opener] Search error: ${message}`);
|
|
325
351
|
res.statusCode = 500;
|
|
326
|
-
res.end('Search failed: ' +
|
|
352
|
+
res.end('Search failed: ' + message);
|
|
327
353
|
}
|
|
328
354
|
return;
|
|
329
355
|
}
|
|
@@ -347,7 +373,7 @@ server
|
|
|
347
373
|
}
|
|
348
374
|
})
|
|
349
375
|
.on('error', (err) => {
|
|
350
|
-
if (err.code === 'EADDRINUSE') {
|
|
376
|
+
if (isErrnoException(err) && err.code === 'EADDRINUSE') {
|
|
351
377
|
console.log(`[file-opener] Port ${PORT} already in use - another file:opener is already running`);
|
|
352
378
|
process.exit(0);
|
|
353
379
|
}
|
package/package.json
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ngx-locatorjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "LocatorJs open-in-editor tools for Angular projects",
|
|
5
|
-
"author": "antepost24",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"license": "MIT",
|
|
8
5
|
"keywords": [
|
|
9
6
|
"angular",
|
|
10
|
-
"
|
|
11
|
-
"open-in-editor",
|
|
7
|
+
"component",
|
|
12
8
|
"devtools",
|
|
13
|
-
"
|
|
9
|
+
"locatorjs",
|
|
10
|
+
"open-in-editor"
|
|
14
11
|
],
|
|
12
|
+
"homepage": "https://github.com/Ea-st-ring/ngx-locator#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/Ea-st-ring/ngx-locator/issues"
|
|
15
|
+
},
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"author": "antepost24",
|
|
15
18
|
"repository": {
|
|
16
19
|
"type": "git",
|
|
17
20
|
"url": "git+https://github.com/Ea-st-ring/ngx-locator.git"
|
|
18
21
|
},
|
|
19
|
-
"
|
|
20
|
-
"
|
|
22
|
+
"bin": {
|
|
23
|
+
"locatorjs-config": "dist/node/config-setup.js",
|
|
24
|
+
"locatorjs-open-in-editor": "dist/node/file-opener.js",
|
|
25
|
+
"locatorjs-scan": "dist/node/cmp-scan.js"
|
|
21
26
|
},
|
|
22
|
-
"
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"type": "module",
|
|
23
32
|
"main": "dist/browser/index.js",
|
|
24
33
|
"types": "dist/browser/index.d.ts",
|
|
25
34
|
"exports": {
|
|
@@ -34,35 +43,21 @@
|
|
|
34
43
|
"default": "./dist/browser/auto.js"
|
|
35
44
|
}
|
|
36
45
|
},
|
|
37
|
-
"bin": {
|
|
38
|
-
"locatorjs-open-in-editor": "dist/node/file-opener.js",
|
|
39
|
-
"locatorjs-config": "dist/node/config-setup.js",
|
|
40
|
-
"locatorjs-scan": "dist/node/cmp-scan.js"
|
|
41
|
-
},
|
|
42
|
-
"files": [
|
|
43
|
-
"dist",
|
|
44
|
-
"README.md"
|
|
45
|
-
],
|
|
46
46
|
"scripts": {
|
|
47
47
|
"build": "npm run build:browser && npm run build:node",
|
|
48
48
|
"build:browser": "tsc -p tsconfig.browser.json",
|
|
49
49
|
"build:node": "tsc -p tsconfig.node.json",
|
|
50
50
|
"clean": "rm -rf dist",
|
|
51
51
|
"prepare": "npm run build",
|
|
52
|
-
"
|
|
53
|
-
"format": "
|
|
54
|
-
"format:check": "prettier --check \"**/*.{ts,tsx,js,jsx,json,md}\""
|
|
52
|
+
"format": "oxfmt",
|
|
53
|
+
"format:check": "oxfmt --check"
|
|
55
54
|
},
|
|
56
55
|
"dependencies": {
|
|
57
|
-
"
|
|
56
|
+
"glob": "^13.0.6"
|
|
58
57
|
},
|
|
59
58
|
"devDependencies": {
|
|
60
|
-
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
61
|
-
"@typescript-eslint/parser": "^7.18.0",
|
|
62
59
|
"@types/node": "^18.18.0",
|
|
63
|
-
"
|
|
64
|
-
"eslint-config-prettier": "^9.1.0",
|
|
65
|
-
"prettier": "^3.2.5",
|
|
60
|
+
"oxfmt": "^0.35.0",
|
|
66
61
|
"typescript": "^5.5.4"
|
|
67
62
|
}
|
|
68
63
|
}
|