@helfy/helfy 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +102 -174
- package/package.json +2 -3
- package/dist/ts-plugin/index.js +0 -12
package/README.md
CHANGED
|
@@ -42,6 +42,26 @@ Helfy -- TypeScript UI-фреймворк с декоратор-ориентир
|
|
|
42
42
|
|
|
43
43
|
## Установка
|
|
44
44
|
|
|
45
|
+
### Создание нового проекта (helfy-create)
|
|
46
|
+
|
|
47
|
+
Быстрый старт — создать проект одной командой:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx helfy-create my-app
|
|
51
|
+
cd my-app
|
|
52
|
+
npm run dev
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Без имени (создаст папку `helfy-app`):
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx helfy-create
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Опция `--skip-install` — создать без `npm install` (для оффлайна или своего registry).
|
|
62
|
+
|
|
63
|
+
### Добавление в существующий проект
|
|
64
|
+
|
|
45
65
|
```bash
|
|
46
66
|
npm install @helfy/helfy
|
|
47
67
|
```
|
|
@@ -96,12 +116,12 @@ Babel-плагин автоматически запускает DI-сканер
|
|
|
96
116
|
"jsx": "preserve",
|
|
97
117
|
"experimentalDecorators": true,
|
|
98
118
|
"emitDecoratorMetadata": true,
|
|
99
|
-
"plugins": [{ "name": "@helfy/helfy
|
|
119
|
+
"plugins": [{ "name": "@helfy/helfy-ts-plugin" }]
|
|
100
120
|
}
|
|
101
121
|
}
|
|
102
122
|
```
|
|
103
123
|
|
|
104
|
-
Плагин `@helfy/helfy
|
|
124
|
+
Плагин `@helfy/helfy-ts-plugin` даёт поддержку директив `@if`, `@for`, `@ref`, `@bind`, `@field` в IDE (автодополнение, типизация, переход к определению). Устанавливается отдельно: `npm install @helfy/helfy-ts-plugin`.
|
|
105
125
|
|
|
106
126
|
---
|
|
107
127
|
|
|
@@ -172,11 +192,11 @@ class Button {
|
|
|
172
192
|
<Button label="Нажми" onClick={() => console.log('clicked')} />
|
|
173
193
|
```
|
|
174
194
|
|
|
175
|
-
При изменении props родителем
|
|
195
|
+
При изменении props родителем обновляются только те DOM-узлы, которые читают изменившиеся props.
|
|
176
196
|
|
|
177
197
|
### Локальное состояние (@state)
|
|
178
198
|
|
|
179
|
-
Декоратор `@state` делает поле
|
|
199
|
+
Декоратор `@state` делает поле реактивным.
|
|
180
200
|
При изменении значения обновляются только те DOM-узлы и эффекты, которые читают это поле (fine-grained). Полный перерендер компонента не происходит:
|
|
181
201
|
|
|
182
202
|
```tsx
|
|
@@ -232,13 +252,24 @@ class App {
|
|
|
232
252
|
|
|
233
253
|
### Монтирование в DOM
|
|
234
254
|
|
|
235
|
-
|
|
255
|
+
Типичный bootstrap — через `createApp()`: создаётся экземпляр, вызывается `attach(root)` внутри, хук `onAttached()` срабатывает после вставки в document.
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
import { createApp } from "@helfy/helfy";
|
|
259
|
+
|
|
260
|
+
createApp({ root: document.getElementById("root")! })
|
|
261
|
+
.router({ routes })
|
|
262
|
+
.mount(App);
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Для сценариев без роутера:
|
|
236
266
|
|
|
237
267
|
```typescript
|
|
238
|
-
|
|
239
|
-
app.attach(document.getElementById('root'));
|
|
268
|
+
createApp({ root: document.getElementById("root")! }).mount(App);
|
|
240
269
|
```
|
|
241
270
|
|
|
271
|
+
Ручное монтирование (без `createApp`): `const app = new App(); app.attach(root)`.
|
|
272
|
+
|
|
242
273
|
### Привязка к DOM и компонентам (@ref)
|
|
243
274
|
|
|
244
275
|
Декоратор `@ref` помечает поле для получения ссылки на DOM-элемент или экземпляр компонента. В JSX используется директива `@ref(this.имяПоля)`. Доступ к ссылке возможен после `onMount()`. Для операций вроде `focus()`, требующих элемент в document, используйте `onAttached()`.
|
|
@@ -377,7 +408,23 @@ export class LoginFormContext {
|
|
|
377
408
|
|
|
378
409
|
**FieldState** содержит `value`, `isDirty`, `isTouched`, `error`, `isValid`. При изменении `value`/`error`/`isTouched` компоненты с `@useForm` перерендериваются.
|
|
379
410
|
|
|
380
|
-
|
|
411
|
+
**Провайдер формы** — родительский компонент оборачивает форму в контекст:
|
|
412
|
+
|
|
413
|
+
```tsx
|
|
414
|
+
// LoginPage.tsx
|
|
415
|
+
@View
|
|
416
|
+
export class LoginPage {
|
|
417
|
+
render() {
|
|
418
|
+
return (
|
|
419
|
+
<LoginFormContext>
|
|
420
|
+
<LoginForm />
|
|
421
|
+
</LoginFormContext>
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Компонент формы** — инжект через `@useForm`, доступ к полям через `this.form`:
|
|
381
428
|
|
|
382
429
|
```tsx
|
|
383
430
|
import { View, useForm } from "@helfy/helfy";
|
|
@@ -389,23 +436,23 @@ export class LoginForm {
|
|
|
389
436
|
|
|
390
437
|
render() {
|
|
391
438
|
return (
|
|
392
|
-
<
|
|
393
|
-
<
|
|
394
|
-
|
|
395
|
-
{this.form.email.
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
</form>
|
|
403
|
-
</LoginFormContext>
|
|
439
|
+
<form onsubmit={(e: Event) => { e.preventDefault(); this.form.submit(); }}>
|
|
440
|
+
<input @field(this.form.email) type="email" class="input" />
|
|
441
|
+
{this.form.email.isTouched && this.form.email.error && (
|
|
442
|
+
<span class="error">{this.form.email.error}</span>
|
|
443
|
+
)}
|
|
444
|
+
<input @field(this.form.password) type="password" class="input" />
|
|
445
|
+
<input @field(this.form.rememberMe) type="checkbox" id="remember" />
|
|
446
|
+
<label for="remember">Запомнить меня</label>
|
|
447
|
+
<button type="submit">Войти</button>
|
|
448
|
+
</form>
|
|
404
449
|
);
|
|
405
450
|
}
|
|
406
451
|
}
|
|
407
452
|
```
|
|
408
453
|
|
|
454
|
+
Компоненты-обёртки (TextField, CheckboxField и т.п.) принимают `field` как prop: `<TextField field={this.form.email} label="Email" />` и используют внутри `<input @field(this.props.field) />`.
|
|
455
|
+
|
|
409
456
|
**JSX-директива `@field(expr)`** — одна директива заменяет `@bind` + `onblur` + `class` для ошибок + `aria-invalid`. Компилятор генерирует:
|
|
410
457
|
|
|
411
458
|
- `value`/`checked` и `oninput`/`onchange`
|
|
@@ -419,7 +466,7 @@ export class LoginForm {
|
|
|
419
466
|
|
|
420
467
|
## Шаблонные директивы
|
|
421
468
|
|
|
422
|
-
Helfy расширяет JSX директивами `@if`, `@elseif`, `@else`, `@for`, `@empty`.
|
|
469
|
+
Helfy расширяет JSX директивами `@if`, `@elseif`, `@else`, `@for`, `@empty`.
|
|
423
470
|
|
|
424
471
|
### @if / @elseif / @else
|
|
425
472
|
|
|
@@ -749,7 +796,18 @@ class ModeDisplay {
|
|
|
749
796
|
|
|
750
797
|
### Реактивные поля
|
|
751
798
|
|
|
752
|
-
`@provide({ reactive: true })` делает поле реактивным: при изменении все потребители
|
|
799
|
+
`@provide({ reactive: true })` делает поле реактивным: при изменении все потребители перерендериваются. Для методов достаточно `@provide()` без `reactive`.
|
|
800
|
+
|
|
801
|
+
**Вычисляемые поля** — геттеры с `@provide({ computed: true, deps: ["field1", "field2"] })` пересчитываются при изменении зависимостей и триггерят перерендер потребителей:
|
|
802
|
+
|
|
803
|
+
```tsx
|
|
804
|
+
@provide({ computed: true, deps: ["todos", "filter"] })
|
|
805
|
+
get filteredTodos(): Todo[] {
|
|
806
|
+
return this.filter === "active"
|
|
807
|
+
? this.todos.filter(t => !t.completed)
|
|
808
|
+
: this.todos;
|
|
809
|
+
}
|
|
810
|
+
```
|
|
753
811
|
|
|
754
812
|
### Опциональная инжекция
|
|
755
813
|
|
|
@@ -896,12 +954,13 @@ import styles from './App.module.css';
|
|
|
896
954
|
| `@observable` | Поле | Делает поле store реактивным -- запись уведомляет подписчиков |
|
|
897
955
|
| `@observe(store, field)` | Поле | Связывает поле компонента с полем store |
|
|
898
956
|
| `@Context` | Класс | Не-рендерящий провайдер контекста; рендерит только детей |
|
|
899
|
-
| `@provide()` / `@provide({ reactive: true })` | Поле | Помечает поле как доступное для `@ctx`
|
|
957
|
+
| `@provide()` / `@provide({ reactive: true })` / `@provide({ computed: true, deps })` | Поле | Помечает поле как доступное для `@ctx`. `reactive` — потребители перерендериваются при изменении; `computed` + `deps` — для геттеров |
|
|
900
958
|
| `@ctx(ContextClass)` / `@ctx(ContextClass, field)` | Поле | Инжектирует контекст или поле контекста из ближайшего провайдера вверх по дереву |
|
|
901
959
|
| `@Injectable<IX>()` / `@Injectable<IX>('singleton' \| 'transient' \| 'scoped')` / `@Injectable(token)` | Класс | Помечает класс как injectable. Scope в (): `'singleton'` (по умолчанию), `'transient'`, `'scoped'`. Fallback: `@Injectable(token)` с Symbol/строкой |
|
|
902
960
|
| `@inject(token)` | Параметр конструктора | Задаёт токен для параметра (fallback; при `@Injectable<IX>()` плагин подставляет токен автоматически) |
|
|
903
961
|
| `@logger()` / `@logger("tag")` | Поле | Инжектирует ILogger. Без аргумента — compile-time имя класса и цвет по типу (View/Context/Store/Injectable). С аргументом — кастомный тег (серый) |
|
|
904
962
|
| `@ref` | Поле | Помечает поле для получения ссылки на DOM или компонент (использовать с `@ref(this.имяПоля)` в JSX) |
|
|
963
|
+
| `@expose` | Метод | Делает метод доступным родителю при `@ref` на компонент (без `@expose` родитель получает экземпляр целиком) |
|
|
905
964
|
| `@binded(name)` | Поле | Связывает поле с биндингом `@bind:name` от родителя (для кастомных компонентов) |
|
|
906
965
|
| `@bind(expr)` / `@bind:name(expr)` | JSX | Двустороннее связывание с `@state` полем (value/checked + oninput/onchange). Для компонентов: `@bind:value(expr)` |
|
|
907
966
|
| `@Form` | Класс | Контекст формы с полями `@field` |
|
|
@@ -909,93 +968,20 @@ import styles from './App.module.css';
|
|
|
909
968
|
| `@useForm(FormContext)` | Поле | Инжектирует форму в компонент с подпиской на изменения полей |
|
|
910
969
|
| `@field(expr)` | JSX | Подключает инпут к FieldState: value/checked + onblur + error class + aria-invalid |
|
|
911
970
|
|
|
912
|
-
### Экспорты пакета
|
|
913
|
-
|
|
914
|
-
```typescript
|
|
915
|
-
import {
|
|
916
|
-
$, // утилиты рендеринга ($._if, $._ifelse, $._forin, $._slot, $._callSlot)
|
|
917
|
-
View, // декоратор @View
|
|
918
|
-
state, // декоратор @state (signal-backed локальное состояние)
|
|
919
|
-
Store, // декоратор @Store
|
|
920
|
-
observable, // декоратор @observable
|
|
921
|
-
observe, // декоратор @observe
|
|
922
|
-
computed, // @computed для Store/@Context/@View (getter-based)
|
|
923
|
-
effect, // @effect для реактивных сайд-эффектов во View
|
|
924
|
-
Context, // декоратор @Context
|
|
925
|
-
provide, // декоратор @provide
|
|
926
|
-
ctx, // декоратор @ctx (поле, Context)
|
|
927
|
-
Container, // DI-контейнер
|
|
928
|
-
Injectable, // декоратор @Injectable
|
|
929
|
-
inject, // декоратор @inject (параметр конструктора)
|
|
930
|
-
createViewInstance,
|
|
931
|
-
setRootContainer,
|
|
932
|
-
getRootContainer,
|
|
933
|
-
ref, // декоратор @ref
|
|
934
|
-
binded, // декоратор @binded (для компонентов с @bind:value)
|
|
935
|
-
Form, // декоратор @Form (контекст формы)
|
|
936
|
-
field, // декоратор @field (поле FormContext)
|
|
937
|
-
useForm, // декоратор @useForm (инжект формы)
|
|
938
|
-
type FieldState,
|
|
939
|
-
type FieldOptions,
|
|
940
|
-
StoreBase, // базовый класс Store (для расширения)
|
|
941
|
-
Subscriber, // тип callback-подписчика
|
|
942
|
-
Router, // ядро роутера (Router)
|
|
943
|
-
RouterContext, // контекст роутера для дерева компонентов
|
|
944
|
-
RouterView, // компонент, рендерящий текущий маршрут
|
|
945
|
-
Link, // SPA-ссылка
|
|
946
|
-
DefaultNotFound, // fallback-компонент 404 (используется RouterView при отсутствии слота)
|
|
947
|
-
path, // @path() — декоратор для pathname
|
|
948
|
-
search, // @search() — декоратор для query-параметров
|
|
949
|
-
params, // @params() — декоратор для route-параметров
|
|
950
|
-
router, // @router() — декоратор для API роутера
|
|
951
|
-
logger, // @logger() — декоратор для ILogger
|
|
952
|
-
LoggerService, // реализация ILogger (DI)
|
|
953
|
-
ConsoleTransport,
|
|
954
|
-
ILoggerToken,
|
|
955
|
-
// primitives для fine-grained reactivity
|
|
956
|
-
createSignal,
|
|
957
|
-
createEffect,
|
|
958
|
-
createComputed,
|
|
959
|
-
batch,
|
|
960
|
-
onCleanup,
|
|
961
|
-
type Signal,
|
|
962
|
-
type SignalGetter,
|
|
963
|
-
type SignalSetter,
|
|
964
|
-
type EffectDisposer,
|
|
965
|
-
type RouteConfig,
|
|
966
|
-
type RouterLocation,
|
|
967
|
-
type ILogger,
|
|
968
|
-
type ILogTransport,
|
|
969
|
-
type LogLevel,
|
|
970
|
-
} from "@helfy/helfy";
|
|
971
|
-
```
|
|
972
|
-
|
|
973
|
-
### Subpath-экспорты
|
|
974
|
-
|
|
975
|
-
| Путь | Назначение |
|
|
976
|
-
|------|------------|
|
|
977
|
-
| `helfy` | Основной API (декораторы, $, типы) |
|
|
978
|
-
| `@helfy/helfy/router` | Тот же API роутера, но отдельным entry (для tree-shaking) |
|
|
979
|
-
| `@helfy/helfy/jsx-runtime` | JSX runtime (`jsx`, `jsxs`) |
|
|
980
|
-
| `@helfy/helfy/compiler/helfy-loader` | Webpack-loader для директив `@if`/`@for`/`@ref`/`@bind`/`@field` |
|
|
981
|
-
| `@helfy/helfy/babel-preset` | Babel-пресет (JSX, TypeScript, декораторы) |
|
|
982
|
-
|
|
983
971
|
### Роутинг (SPA)
|
|
984
972
|
|
|
985
|
-
Helfy включает лёгкий SPA
|
|
973
|
+
Helfy включает лёгкий SPA‑роутер. При вызове `createApp().router({ routes }).mount(App)` фреймворк автоматически оборачивает приложение в `RouterContext`, поэтому свой App не нужно оборачивать вручную:
|
|
986
974
|
|
|
987
975
|
```tsx
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
// Конфиг маршрутов
|
|
976
|
+
// index.ts
|
|
977
|
+
createApp({ root: document.getElementById("root")! })
|
|
978
|
+
.router({ routes })
|
|
979
|
+
.mount(App);
|
|
980
|
+
```
|
|
981
|
+
|
|
982
|
+
```tsx
|
|
983
|
+
import { View, RouterView, Link, path, type RouteConfig } from "@helfy/helfy";
|
|
984
|
+
|
|
999
985
|
const routes: RouteConfig[] = [
|
|
1000
986
|
{ path: "/", component: HomePage },
|
|
1001
987
|
{ path: "/analytics", component: AnalyticsPage },
|
|
@@ -1007,38 +993,27 @@ const routes: RouteConfig[] = [
|
|
|
1007
993
|
class App {
|
|
1008
994
|
render() {
|
|
1009
995
|
return (
|
|
1010
|
-
<
|
|
1011
|
-
<
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
</Layout>
|
|
1015
|
-
</RouterContext>
|
|
996
|
+
<Layout>
|
|
997
|
+
@slot.sidebar() {<Sidebar />}
|
|
998
|
+
@slot.content() {<RouterView />}
|
|
999
|
+
</Layout>
|
|
1016
1000
|
);
|
|
1017
1001
|
}
|
|
1018
1002
|
}
|
|
1019
1003
|
|
|
1020
1004
|
@View
|
|
1021
1005
|
class Sidebar {
|
|
1022
|
-
@
|
|
1023
|
-
private
|
|
1006
|
+
@path()
|
|
1007
|
+
private pathname!: string;
|
|
1024
1008
|
|
|
1025
1009
|
render() {
|
|
1026
|
-
const
|
|
1027
|
-
const
|
|
1028
|
-
const isAnalytics = pathname.startsWith("/analytics");
|
|
1010
|
+
const isHome = this.pathname === "/";
|
|
1011
|
+
const isAnalytics = this.pathname.startsWith("/analytics");
|
|
1029
1012
|
|
|
1030
1013
|
return (
|
|
1031
1014
|
<nav>
|
|
1032
|
-
<Link
|
|
1033
|
-
|
|
1034
|
-
label="Главная"
|
|
1035
|
-
class={isHome ? "font-bold" : ""}
|
|
1036
|
-
/>
|
|
1037
|
-
<Link
|
|
1038
|
-
to="/analytics"
|
|
1039
|
-
label="Аналитика"
|
|
1040
|
-
class={isAnalytics ? "font-bold" : ""}
|
|
1041
|
-
/>
|
|
1015
|
+
<Link to="/" label="Главная" class={isHome ? "font-bold" : ""} />
|
|
1016
|
+
<Link to="/analytics" label="Аналитика" class={isAnalytics ? "font-bold" : ""} />
|
|
1042
1017
|
</nav>
|
|
1043
1018
|
);
|
|
1044
1019
|
}
|
|
@@ -1080,13 +1055,6 @@ class DebugPage {
|
|
|
1080
1055
|
}
|
|
1081
1056
|
```
|
|
1082
1057
|
|
|
1083
|
-
Под капотом:
|
|
1084
|
-
|
|
1085
|
-
- `Router` использует `history.pushState/replaceState` и `popstate` для синхронизации с URL.
|
|
1086
|
-
- `RouterContext` хранит реактивное `location` (`@provide({ reactive: true })`), так что `@ctx(RouterContext, "location")` и декораторы `@path/@search/@params/@router` автоматически триггерят перерендер компонентов при смене маршрута.
|
|
1087
|
-
- `RouterView` сопоставляет текущий `pathname` с `RouteConfig` (в том числе с параметрами `:id` и вложенными маршрутами) и рендерит нужный `@View`‑класс. При отсутствии совпадения показывается `DefaultNotFound` или содержимое слота `@slot.notFound`.
|
|
1088
|
-
- `Link` перехватывает `click`, не перезагружает страницу и вызывает `router.push/replace`, сохраняя поведение обычных ссылок (`href` остаётся).
|
|
1089
|
-
|
|
1090
1058
|
**Кастомная страница 404.** Оберните `RouterView` и переопределите слот `notFound`:
|
|
1091
1059
|
|
|
1092
1060
|
```tsx
|
|
@@ -1147,46 +1115,6 @@ class SearchInput {
|
|
|
1147
1115
|
}
|
|
1148
1116
|
```
|
|
1149
1117
|
|
|
1150
|
-
### Утилиты рендеринга ($)
|
|
1151
|
-
|
|
1152
|
-
Компилятор трансформирует директивы в вызовы `$`, но их можно использовать и напрямую.
|
|
1153
|
-
|
|
1154
|
-
**Статические** (условие вычисляется один раз):
|
|
1155
|
-
|
|
1156
|
-
```tsx
|
|
1157
|
-
import { $ } from "@helfy/helfy";
|
|
1158
|
-
|
|
1159
|
-
render() {
|
|
1160
|
-
return (
|
|
1161
|
-
<div>
|
|
1162
|
-
{$._if(this.visible, <span>Видно</span>)}
|
|
1163
|
-
{$._ifelse(this.count > 0,
|
|
1164
|
-
<span>Положительное</span>,
|
|
1165
|
-
<span>Отрицательное или ноль</span>
|
|
1166
|
-
)}
|
|
1167
|
-
{$._forin(this.items, (item, index) => (
|
|
1168
|
-
<div $_key={item.id}>{index}: {item.name}</div>
|
|
1169
|
-
))}
|
|
1170
|
-
</div>
|
|
1171
|
-
);
|
|
1172
|
-
}
|
|
1173
|
-
```
|
|
1174
|
-
|
|
1175
|
-
**Реактивные** (условие и ветки — thunks, пересчитываются при изменении signals):
|
|
1176
|
-
|
|
1177
|
-
```tsx
|
|
1178
|
-
{$._rIf(() => this.visible, () => <span>Видно</span>)}
|
|
1179
|
-
{$._rIfElse(() => this.count > 0,
|
|
1180
|
-
() => <span>Положительное</span>,
|
|
1181
|
-
() => <span>Отрицательное или ноль</span>
|
|
1182
|
-
)}
|
|
1183
|
-
{$._rForin(() => this.items, (item, index) => (
|
|
1184
|
-
<div $_key={item.id}>{index}: {item.name}</div>
|
|
1185
|
-
))}
|
|
1186
|
-
```
|
|
1187
|
-
|
|
1188
|
-
Компилятор автоматически выбирает реактивный вариант (`_rIf`, `_rIfElse`, `_rForin`) при генерации кода из директив `@if` / `@for`.
|
|
1189
|
-
|
|
1190
1118
|
### Слоты (content projection)
|
|
1191
1119
|
|
|
1192
1120
|
Helfy поддерживает именованные слоты с fallback‑содержимым и переопределением в дочерних компонентах.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helfy/helfy",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "TypeScript UI framework with decorator API, custom JSX and reactive state management",
|
|
5
5
|
"author": "ikrymsaev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -40,8 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"./compiler/helfy-loader": "./dist/compiler/helfy-loader.js",
|
|
42
42
|
"./compiler/babel": "./dist/compiler/babel.js",
|
|
43
|
-
"./babel-preset": "./babel-preset.js"
|
|
44
|
-
"./ts-plugin": "./dist/ts-plugin/index.js"
|
|
43
|
+
"./babel-preset": "./babel-preset.js"
|
|
45
44
|
},
|
|
46
45
|
"files": [
|
|
47
46
|
"dist",
|
package/dist/ts-plugin/index.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";var xe=Object.defineProperty,me=Object.defineProperties;var we=Object.getOwnPropertyDescriptors;var Y=Object.getOwnPropertySymbols;var be=Object.prototype.hasOwnProperty,ve=Object.prototype.propertyIsEnumerable;var H=(t,s,e)=>s in t?xe(t,s,{enumerable:!0,configurable:!0,writable:!0,value:e}):t[s]=e,L=(t,s)=>{for(var e in s||(s={}))be.call(s,e)&&H(t,e,s[e]);if(Y)for(var e of Y(s))ve.call(s,e)&&H(t,e,s[e]);return t},A=(t,s)=>me(t,we(s));var k=(t,s)=>()=>(s||t((s={exports:{}}).exports,s),s.exports);var R=k((st,N)=>{"use strict";var _e=/@[A-Za-z_$][\w$]*/,Ee=/^\s*@(if|for)\b/,ye=/^\s*@(elseif|else|empty)\b/,Te=/^\s*@slot(?::|\.)[A-Za-z_$][\w$]*/,Ce=".__helfy__.ts";N.exports={DIRECTIVE_RE:_e,CHAIN_START_RE:Ee,CHAIN_CONT_RE:ye,SLOT_USAGE_RE:Te,VIRTUAL_SUFFIX:Ce}});var j=k((it,ie)=>{"use strict";function Le(t){let s=Fe(t);return s=Pe(s),s=Ie(s),s=ee(s),s}function Ae(t){let s=[],e=/@ref\s*\(\s*this\s*\.\s*([A-Za-z_$][\w$]*)\s*\)/g,n;for(;(n=e.exec(t))!==null;){let a=n[1],f=`ref={(el: typeof this.${a})=>this.${a}=el}`;s.push({start:n.index,end:n.index+n[0].length,newLen:f.length,exprStart:n.index+5,exprEnd:n.index+n[0].length-1,newExprStart:14})}let i=/@bind:([A-Za-z_$][\w$]*)\s*\(/g;for(;(n=i.exec(t))!==null;){let a=1,f=n.index+n[0].length;f=P(t,f);let h=n.index+n[0].length,p=f-1,c=t.slice(h,p).trim(),d=`$_bind_${n[1]}={${c}}`;s.push({start:n.index,end:f,newLen:d.length,exprStart:h,exprEnd:p,newExprStart:7+n[1].length+2})}let r=/@bind\s*\(/g;for(;(n=r.exec(t))!==null;){let a=n.index,f=P(t,n.index+n[0].length),h=n.index+n[0].length,p=f-1,c=t.slice(h,p).trim(),$=Z(t,a)?"onInput":"oninput",S=`value={${c}} ${$}={(e: Event & { target: { value: string } })=>${c}=e.target.value as typeof ${c}}`;s.push({start:a,end:f,newLen:S.length,exprStart:h,exprEnd:p,newExprStart:7})}let l=/@field\s*\(/g;for(;(n=l.exec(t))!==null;){let a=n.index,f=P(t,n.index+n[0].length),h=n.index+n[0].length,p=f-1,c=t.slice(h,p).trim();if(!O(c))continue;let d=M(t,a);if(!d)continue;let $=te(t,a),S=$?ne($.content,t,$.start):null,x=S?`[${S.expr}, ${c}?.isTouched && ${c}?.error && 'input-error'].filter(Boolean).join(' ')`:`${c}?.isTouched && ${c}?.error ? 'input-error' : undefined`;S&&s.push({start:S.start,end:S.end,newLen:0,exprStart:S.start,exprEnd:S.end,newExprStart:0});let m=c+".value",b=`() => { ${c}.isTouched = true; }`,T=`${c}?.isTouched && ${c}?.error ? "true" : "false"`,_;if(d.isComponent)_=`value={${m}} onInput={(e: Event & { target: HTMLInputElement })=>${m}=e.target.value} onBlur={${b}} class={${x}} aria-invalid={${T}}`;else if(d.tag==="input"&&(d.type==="checkbox"||d.type==="radio"))_=`checked={${m}} onchange={(e: Event & { target: HTMLInputElement })=>${m}=e.target.checked} onblur={${b}} class={${x}} aria-invalid={${T}}`;else if(d.tag==="select")_=`value={${m}} onchange={(e: Event & { target: HTMLSelectElement })=>${m}=e.target.value} onblur={${b}} class={${x}} aria-invalid={${T}}`;else{let C=d.tag==="textarea"?"HTMLTextAreaElement":"HTMLInputElement";_=`value={${m}} oninput={(e: Event & { target: ${C} })=>${m}=e.target.value} onblur={${b}} class={${x}} aria-invalid={${T}}`}s.push({start:a,end:f,newLen:_.length,exprStart:h,exprEnd:p,newExprStart:7})}let o=/@slot\.([A-Za-z_$][\w$]*)\s*\(/g;for(;(n=o.exec(t))!==null;){let a=n.index,f=a+6+n[1].length;if(f=D(t,f),t[f]!=="(")continue;let h=re(t,f);if(h<0)continue;let p=t.slice(f+1,h).trim()||"_";p.includes(":")&&(p=p.split(/\s*:\s*[\[{(]/)[0].trim()||"_");let c=D(t,h+1);if(t[c]!=="{")continue;let d=se(t,c);if(d<0)continue;let $=t.slice(c+1,d),S=`{ ((${p}: any) => (${$}))(null as any) }`,x=4+p.length+11;s.push({start:a,end:d+1,newLen:S.length,exprStart:c+1,exprEnd:d,newExprStart:x})}return s.sort((a,f)=>a.start-f.start),{origToTrans:a=>{let f=0,h=0;for(let p of s){let c=p.start-h;if(h+c>a)return f+(a-h);if(f+=c,h=p.start,a<p.end)return a>=p.exprStart&&a<p.exprEnd?f+p.newExprStart+(a-p.exprStart):f;f+=p.newLen,h=p.end}return f+(a-h)},transToOrig:a=>{let f=0,h=0;for(let p of s){let c=p.start-h;if(f+c>a)return h+(a-f);if(f+=c,h=p.start,f+p.newLen>a){let d=a-f,$=p.exprEnd-p.exprStart;return d>=p.newExprStart&&d<p.newExprStart+$?p.exprStart+(d-p.newExprStart):p.start}f+=p.newLen,h=p.end}return h+(a-f)}}}function Fe(t){let s=/@ref\s*\(\s*this\s*\.\s*([A-Za-z_$][\w$]*)\s*\)/g,e,n=[];for(;(e=s.exec(t))!==null;){let i=e[1];n.push({start:e.index,end:e.index+e[0].length,code:`ref={(el: typeof this.${i})=>this.${i}=el}`})}return z(t,n)}function Pe(t){let s=t,e=/@bind:([A-Za-z_$][\w$]*)\s*\(/g,n,i=[];for(;(n=e.exec(s))!==null;){let o=P(s,n.index+n[0].length),g=s.slice(n.index+n[0].length,o-1).trim();i.push({start:n.index,end:o,code:`$_bind_${n[1]}={${g}}`})}s=z(s,i);let r=/@bind\s*\(/g,l=[];for(;(n=r.exec(s))!==null;){let o=n.index,g=P(s,n.index+n[0].length),u=s.slice(n.index+n[0].length,g-1).trim(),a=M(s,o),f=O(u),h=f?u+".value":u,p=f?u+".value":u,c;if(a&&a.tag==="input"&&(a.type==="checkbox"||a.type==="radio"))c=`checked={${h}} onchange={(e)=>${p}=e.target.checked}`;else{let d=Z(s,o)?"onInput":"oninput";c=`value={${h}} ${d}={(e: Event & { target: { value: string } })=>${p}=e.target.value}`}l.push({start:o,end:g,code:c})}return s=z(s,l),s}function Ie(t){let s=/@field\s*\(/g,e,n=[];for(;(e=s.exec(t))!==null;){let r=e.index,l=P(t,e.index+e[0].length),o=t.slice(e.index+e[0].length,l-1).trim();if(!O(o))continue;let g=M(t,r);if(!g)continue;let u=te(t,r),a=u?ne(u.content,t,u.start):null,f=a?`[${a.expr}, ${o}?.isTouched && ${o}?.error && 'input-error'].filter(Boolean).join(' ')`:`${o}?.isTouched && ${o}?.error ? 'input-error' : undefined`;a&&n.push({start:a.start,end:a.end,code:""});let h=o+".value",p=`() => { ${o}.isTouched = true; }`,c=`${o}?.isTouched && ${o}?.error ? "true" : "false"`,d;if(g.isComponent)d=`value={${h}} onInput={(e: Event & { target: HTMLInputElement })=>${h}=e.target.value} onBlur={${p}} class={${f}} aria-invalid={${c}}`;else if(g.tag==="input"&&(g.type==="checkbox"||g.type==="radio"))d=`checked={${h}} onchange={(e: Event & { target: HTMLInputElement })=>${h}=e.target.checked} onblur={${p}} class={${f}} aria-invalid={${c}}`;else if(g.tag==="select")d=`value={${h}} onchange={(e: Event & { target: HTMLSelectElement })=>${h}=e.target.value} onblur={${p}} class={${f}} aria-invalid={${c}}`;else{let $=g.tag==="textarea"?"HTMLTextAreaElement":"HTMLInputElement";d=`value={${h}} oninput={(e: Event & { target: ${$} })=>${h}=e.target.value} onblur={${p}} class={${f}} aria-invalid={${c}}`}n.push({start:r,end:l,code:d})}n.sort((r,l)=>l.start-r.start);let i=t;for(let r of n)i=i.slice(0,r.start)+r.code+i.slice(r.end);return i}function ee(t){let s="",e=0,n=/@slot\.([A-Za-z_$][\w$]*)\s*\(/g,i;for(;(i=n.exec(t))!==null;){s+=t.slice(e,i.index),e=i.index;let r=i.index+6+i[1].length;if(r=D(t,r),t[r]!=="("){s+=t[e],e++,n.lastIndex=e;continue}let l=re(t,r);if(l<0){s+=t[e],e++,n.lastIndex=e;continue}let o=t.slice(r+1,l).trim()||"_";o.includes(":")&&(o=o.split(/\s*:\s*[\[{(]/)[0].trim()||"_");let g=D(t,l+1);if(t[g]!=="{"){s+=t[e],e++,n.lastIndex=e;continue}let u=se(t,g);if(u<0){s+=t[e],e++,n.lastIndex=e;continue}let a=t.slice(g+1,u);s+=`{ ((${o}: any) => (${a}))(null as any) }`,e=u+1}return s+=t.slice(e),s}function Z(t,s){let n=t.slice(Math.max(0,s-200),s).match(new RegExp("<([A-Za-z][A-Za-z0-9]*)\\s[^>]*$","s"));return n?n[1][0]===n[1][0].toUpperCase()&&n[1].length>1:!1}function O(t){return/^this\.([A-Za-z_$][\w$]*\.)+[A-Za-z_$][\w$]*$/.test(t.trim())}function M(t,s){let e=s-1;for(;e>=0;){let n=t[e];if(n==="'"||n==='"'||n==="`"){for(e--;e>=0&&t[e]!==n;)e--;e--;continue}if(n==="<"){for(e++;e<t.length&&/\s/.test(t[e]);)e++;let i=t.slice(e).match(/^([A-Za-z][A-Za-z0-9]*)/);if(!i)return null;let r=i[1],o=t.slice(e,s+200).match(/type\s*=\s*["'](checkbox|radio|text|email|password|search|tel|url)["']/);return{tag:r.toLowerCase(),type:o?o[1].toLowerCase():r.toLowerCase()==="input"?"text":void 0,isComponent:r[0]===r[0].toUpperCase()&&r.length>1}}e--}return null}function te(t,s){let e=s-1;for(;e>=0;){let n=t[e];if(n==="'"||n==='"'||n==="`"){for(e--;e>=0&&t[e]!==n;)e--;e--;continue}if(n==="<"){let i=e,r=e+1;for(;r<t.length;){let l=t[r];if(l==="'"||l==='"'||l==="`"){for(r++;r<t.length&&t[r]!==l;)t[r]==="\\"&&r++,r++;r++;continue}if(l===">")return{start:i,end:r+1,content:t.slice(i,r+1)};if(l==="/"&&t[r+1]===">")return{start:i,end:r+2,content:t.slice(i,r+2)};r++}return null}e--}return null}function ne(t,s,e){let i=/\bclass\s*=\s*(\{|"[^"]*"|'[^']*')/g.exec(t);if(!i)return null;let r=e+i.index,l,o;if(i[1]==="{"){let g=r+i[0].length-1,u=ke(s,g);if(u<0)return null;l=s.slice(g+1,u).trim(),o=u+1}else l=i[1],o=r+i[0].length;return{expr:l,start:r,end:o}}function D(t,s){for(;s<t.length&&/\s/.test(t[s]);)s++;return s}function P(t,s){let e=1,n=s;for(;n<t.length&&e>0;){let i=t[n];if(i==="(")e++;else if(i===")"){if(e--,e===0){n++;break}}else if(i==="'"||i==='"'||i==="`"){n=V(t,n);continue}n++}return n}function re(t,s){let e=1,n=s+1;for(;n<t.length&&e>0;){let i=t[n];if(i==="(")e++;else if(i===")"){if(e--,e===0)return n}else if(i==="'"||i==='"'||i==="`"){n=V(t,n);continue}n++}return-1}function se(t,s){let e=1,n=s+1;for(;n<t.length&&e>0;){let i=t[n];if(i==="{")e++;else if(i==="}"){if(e--,e===0)return n}else if(i==="'"||i==='"'||i==="`"){n=V(t,n);continue}n++}return-1}function ke(t,s){if(t[s]!=="{")return-1;let e=1,n=s+1;for(;n<t.length&&e>0;){let i=t[n];if(i==="{")e++;else if(i==="}")e--;else if(i==="'"||i==='"'||i==="`"){let r=i;for(n++;n<t.length&&t[n]!==r;)t[n]==="\\"&&n++,n++;n++;continue}e>0&&n++}return e===0?n:-1}function V(t,s){let e=t[s],n=s+1;for(;n<t.length;){if(t[n]==="\\"){n+=2;continue}if(t[n]===e)return n+1;if(e==="`"&&t[n]==="$"&&t[n+1]==="{"){n+=2;let i=1;for(;n<t.length&&i>0;)t[n]==="{"?i++:t[n]==="}"&&i--,n++;continue}n++}return n}function z(t,s){let e=t;for(let n=s.length-1;n>=0;n--){let{start:i,end:r,code:l}=s[n];e=e.slice(0,i)+l+e.slice(r)}return e}ie.exports={stripHelfyDirectivesForParse:Le,stripSlotConsumerForParse:ee,buildHelfyPositionMap:Ae,isComponentTagBefore:Z,isFieldStatePath:O,findTagBefore:M}});var ae=k((ot,oe)=>{"use strict";var{CHAIN_START_RE:lt,CHAIN_CONT_RE:ct,SLOT_USAGE_RE:Re,VIRTUAL_SUFFIX:W}=R(),{stripHelfyDirectivesForParse:le}=j();function q(t){let s=t.split(`
|
|
2
|
-
`),e=[],n=!1,i=0,r=!1;for(let l=0;l<s.length;l++){let o=s[l];if(!n){/\brender\s*\(\s*\)\s*\{/.test(o)&&(n=!0,i=1),e.push(o.replace(/@(if|elseif|else|for|empty)\b/g," $1"));continue}if(i+=Ve(o),i<=0){n=!1,r=!1,e.push(o);continue}if(!r){if(/^\s*return\s*\(\s*$/.test(o)){r=!0,e.push(o.replace(/return\s*\(/,g=>"{"+" ".repeat(g.length-1)));continue}e.push(o.replace(/@(if|elseif|else|for|empty)\b/g," $1"));continue}if(/^\s*\)\s*$/.test(o)){r=!1,e.push(o.replace(")","}"));continue}if(Re.test(o)){e.push(ze(o));continue}if(/@(if|elseif|else|for|empty)\b/.test(o)){e.push(/@for\b/.test(o)?je(o):o.replace(/@(if|elseif|else|for|empty)\b/g," $1"));continue}if(/^\s*</.test(o)){e.push(Me(o));continue}e.push(o)}return e.join(`
|
|
3
|
-
`)}function De(t,s){var i,r,l,o,g;function e(u){return typeof u=="string"&&u.endsWith(W)}function n(u){return e(u)?u.slice(0,-W.length):u}return{getCompilationSettings(){return A(L({},t.getCompilationSettings()),{plugins:[]})},getNewLine:()=>{var u;return((u=t.getNewLine)==null?void 0:u.call(t))||`
|
|
4
|
-
`},getProjectVersion:()=>{var u;return((u=t.getProjectVersion)==null?void 0:u.call(t))||"0"},getScriptFileNames(){let u=t.getScriptFileNames(),a=u.filter(f=>f.endsWith(".tsx")).map(f=>f+W);return[...u,...a]},getScriptKind(u){var a,f;return e(u)?s.ScriptKind.TS:(f=(a=t.getScriptKind)==null?void 0:a.call(t,u))!=null?f:s.ScriptKind.Unknown},getScriptVersion(u){let a=t.getScriptVersion(n(u));return e(u)?a+"-v":a},getScriptSnapshot(u){let a=t.getScriptSnapshot(n(u));if(!a)return a;let f=a.getText(0,a.getLength());return e(u)?s.ScriptSnapshot.fromString(q(f)):u.endsWith(".tsx")&&ce(f)?s.ScriptSnapshot.fromString(le(f)):a},getCurrentDirectory:()=>t.getCurrentDirectory(),getDefaultLibFileName:u=>t.getDefaultLibFileName(u),fileExists(u){var a,f,h,p;if(e(u)){let c=n(u);return(f=(a=t.fileExists)==null?void 0:a.call(t,c))!=null?f:!!t.getScriptSnapshot(c)}return(p=(h=t.fileExists)==null?void 0:h.call(t,u))!=null?p:!1},readFile(u,a){var h;let f=(h=t.readFile)==null?void 0:h.call(t,n(u),a);return f==null?f:e(u)?q(f):u.endsWith(".tsx")&&ce(f)?le(f):f},resolveModuleNames:t.resolveModuleNames?(u,a,...f)=>t.resolveModuleNames(u,n(a),...f):void 0,resolveTypeReferenceDirectives:(i=t.resolveTypeReferenceDirectives)==null?void 0:i.bind(t),getResolvedModuleWithFailedLookupLocationsFromCache:(r=t.getResolvedModuleWithFailedLookupLocationsFromCache)==null?void 0:r.bind(t),readDirectory:(l=t.readDirectory)==null?void 0:l.bind(t),directoryExists:(o=t.directoryExists)==null?void 0:o.bind(t),getDirectories:(g=t.getDirectories)==null?void 0:g.bind(t),useCaseSensitiveFileNames:()=>{var u,a;return(a=(u=t.useCaseSensitiveFileNames)==null?void 0:u.call(t))!=null?a:!1}}}function Oe(t,s){let{line:e,character:n}=t.getLineAndCharacterOfPosition(s),i=t.getFullText().split(`
|
|
5
|
-
`);if(!/@for\b/.test(i[e]))return null;let r=Ze(i[e]);if(!r)return null;let{indentLen:l,el:o,idx:g,iterTrimmed:u,elOrig:a,idxOrig:f,iterOrig:h,trackElOrig:p,elVirt:c,iterVirt:d,idxVirt:$}=r,S=n-l,x;if(S>=a&&S<a+o.length)x=c+(S-a);else if(g&&f>=0&&S>=f&&S<f+g.length)x=$+(S-f);else if(S>=h&&S<h+u.length)x=d+(S-h);else if(p>=0&&S>=p&&S<p+o.length)x=c+(S-p);else return null;return t.getPositionOfLineAndCharacter(e,l+x)}function ce(t){return t.includes("@bind")||t.includes("@ref(")||t.includes("@field(")||t.includes("@slot.")}function Me(t){let s=t.match(/^\s*/)[0],e=t.slice(s.length),n="",i=0;for(;i<e.length;)if(e[i]==="<")for(n+=" ",i++;i<e.length;)if(e[i]==="{"){let r=0,l=i;for(;l<e.length;){if(e[l]==="{")r++;else if(e[l]==="}"&&(r--,r===0)){l++;break}l++}n+=e.slice(i,l),i=l}else if(e[i]===">"){n+=" ",i++;break}else if(e.startsWith("@bind:",i)){let r=e.slice(i).match(/^@bind:([A-Za-z_$][\w$]*)\s*\(/);if(r){let l=i+r[0].length,o=1;for(;l<e.length&&o>0;)if(e[l]==="(")o++;else if(e[l]===")"){if(o--,o===0){l++;break}}else if(e[l]==="'"||e[l]==='"'||e[l]==="`"){let g=e[l];for(l++;l<e.length&&e[l]!==g;)e[l]==="\\"&&l++,l++;l++}else l++;n+="$_bind_"+r[1]+"={"+e.slice(i+r[0].length,l-1).trim()+"}",i=l}else n+=" ",i++}else if(e.slice(i).match(/^@bind\s*\(/)){let r=e.slice(i).match(/^@bind\s*\(/),l=i+r[0].length,o=1;for(;l<e.length&&o>0;)if(e[l]==="(")o++;else if(e[l]===")"){if(o--,o===0){l++;break}}else if(e[l]==="'"||e[l]==='"'||e[l]==="`"){let g=e[l];for(l++;l<e.length&&e[l]!==g;)e[l]==="\\"&&l++,l++;l++}else l++;n+="value={"+e.slice(i+r[0].length,l-1)+"}",i=l}else if(e.slice(i).match(/^@field\s*\(/)){let r=e.slice(i).match(/^@field\s*\(/),l=i+r[0].length,o=1;for(;l<e.length&&o>0;)if(e[l]==="(")o++;else if(e[l]===")"){if(o--,o===0){l++;break}}else if(e[l]==="'"||e[l]==='"'||e[l]==="`"){let g=e[l];for(l++;l<e.length&&e[l]!==g;)e[l]==="\\"&&l++,l++;l++}else l++;n+="value={"+e.slice(i+r[0].length,l-1).trim()+".value}",i=l}else if(e.startsWith("@ref(",i)){let r=i+5,l=1,o=r;for(;r<e.length&&l>0;)if(e[r]==="(")l++;else if(e[r]===")"){if(l--,l===0){r++;break}}else if(e[r]==="'"||e[r]==='"'||e[r]==="`"){let g=e[r];for(r++;r<e.length&&e[r]!==g;)e[r]==="\\"&&r++,r++;r++}else r++;n+=" "+e.slice(o,r-1)+" ",i=r}else n+=" ",i++;else if(e[i]==="{"){let r=0,l=i;for(;l<e.length;){if(e[l]==="{")r++;else if(e[l]==="}"&&(r--,r===0)){l++;break}l++}n+=e.slice(i,l),i=l}else n+=" ",i++;return s+n}function je(t){let s=t.match(/^(\s*)@for\s*\((.+)\)\s*\{\s*$/);if(!s)return t.replace("@for"," for");let[,e,n]=s,i=n.indexOf(";"),l=(i>=0?n.slice(0,i):n).trim().match(/^(\w+)(?:\s*,\s*(\w+))?\s+of\s+(.+)$/);if(!l)return t.replace("@for"," for");let[,o,g,u]=l,a=t.length-e.length,f;if(g)f=`for (const ${o} of ${u.trim()}) {let ${g}=0;`;else{let h=`for (const ${o} of ${u.trim()})`;f=h+" ".repeat(Math.max(1,a-h.length-1))+"{"}return f.length<a?f+=" ".repeat(a-f.length):f.length>a&&(f=f.slice(0,a)),e+f}function ze(t){let s=t.match(/^(\s*)(.+)$/);if(!s)return t;let[,e,n]=s,i=n.length,l=/^@[A-Za-z_$][\w$]*\s*\([^)]*\)\s*\{\s*$/.test(n)||/^@slot(?::|\.)[A-Za-z_$][\w$]*\s*\([^)]*\)\s*(?:fallback\s*)?\{\s*$/.test(n)?"{":";";return l.length<i?l+=" ".repeat(i-l.length):l.length>i&&(l=l.slice(0,i)),e+l}function Ze(t){let s=t.match(/^(\s*)@for\s*\((.+)\)\s*\{\s*$/);if(!s)return null;let[,e,n]=s,i=n.indexOf(";"),l=(i>=0?n.slice(0,i):n).trim().match(/^(\w+)(?:\s*,\s*(\w+))?\s+of\s+(.+)$/);if(!l)return null;let[,o,g,u]=l,a=u.trim(),f=e.length,h=6,p=g?h+o.length+2:-1,c=h+o.length+(g?2+g.length+4:4),d=-1;if(i>=0){let m=n.slice(i),b=m.match(/;\s*track\s+(\w+)/);b&&(d=6+i+m.indexOf(b[1]))}let $=11,S=$+o.length+4,x=g?$+o.length+4+a.length+7:-1;return{indentLen:f,el:o,idx:g,iterTrimmed:a,elOrig:h,idxOrig:p,iterOrig:c,trackElOrig:d,elVirt:$,iterVirt:S,idxVirt:x}}function Ve(t){let s=0,e=!1,n="";for(let i=0;i<t.length;i++){let r=t[i];if(e){if(r==="\\"){i++;continue}r===n&&(e=!1);continue}if(r==="'"||r==='"'||r==="`"){e=!0,n=r;continue}r==="{"&&s++,r==="}"&&s--}return s}oe.exports={makeVirtual:q,createVirtualHost:De,remapForPosition:Oe}});var pe=k((ut,he)=>{"use strict";var{DIRECTIVE_RE:We,CHAIN_START_RE:qe,CHAIN_CONT_RE:Be,SLOT_USAGE_RE:Ue}=R(),{buildHelfyPositionMap:Qe}=j(),B=new Map;function fe(t){var r;let s=B.get(t);if(s!==void 0)return s;let e=require("fs"),n=l=>{try{return e.readFileSync(l,"utf8")}catch(o){return null}},i=(r=n(t.replace(/\//g,"\\")))!=null?r:n(t.replace(/\\/g,"/"));return B.set(t,i),setTimeout(()=>B.delete(t),0),i}function Ge(t,s,e){if(!e.length||!s.endsWith(".tsx"))return e;let n=fe(s);if(!n||!We.test(n))return e;let i=de(n.split(`
|
|
6
|
-
`)),r=t.getProgram(),l=r&&r.getSourceFile(s);if(!l&&r){let h=s.replace(/\\/g,"/").toLowerCase();for(let p of r.getSourceFiles()){let c=p.fileName.replace(/\\/g,"/").toLowerCase();if(c===h||c.endsWith(h.replace(/^[a-z]:/,""))||h.endsWith(c.replace(/^[a-z]:/,""))){l=p;break}}}let o=l?l.getFullText():n,g=U(o.split(`
|
|
7
|
-
`)),u=n.split(`
|
|
8
|
-
`),a=U(u),f=u.map((h,p)=>a.has(p)?h:"").join(`
|
|
9
|
-
`);return e.filter(h=>{if(h.start==null)return!0;if(l){let p=l.getLineAndCharacterOfPosition(h.start).line;if(g.has(p))return!1}if(h.code===1109&&i.size>0)return!1;if(h.code===6198||h.code===6133||h.code===2304){let p=o.slice(h.start,h.start+(h.length||0)).trim(),c=(p.match(/^[a-zA-Z_$][a-zA-Z0-9_$]*/)||[p])[0];if(!c)return!0;let d=c.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");if(i.has(c)||new RegExp("\\b"+d+"\\b").test(f)||h.code===2304&&new RegExp("@slot\\.\\w+\\s*\\(\\s*\\{[^}]*\\b"+d+"\\b").test(n))return!1}return!0})}function Ke(t,s,e){if(!e||!e.has(t)||!s.length)return s;let n=e.get(t),i=Qe(n.original);return s.map(r=>{var g;if(r.start==null)return r;let l=i.transToOrig(r.start),o=i.transToOrig(r.start+((g=r.length)!=null?g:0));return A(L({},r),{start:l,length:Math.max(0,o-l)})})}function U(t){let s=new Set,e=0;for(;e<t.length;)if(qe.test(t[e])){let n=ue(t,e);for(let i=e;i<=n;i++)s.add(i);e=n+1}else if(Xe(t[e]))if(/\{\s*\r?$/.test(t[e])){let i=ue(t,e);for(let r=e;r<=i;r++)s.add(r);e=i+1}else s.add(e++);else if(/@ref\s*\(/.test(t[e])){e>0&&/<\s*[A-Za-z_]/.test(t[e-1])&&!/>\s*$/.test(t[e-1].trim())&&s.add(e-1),s.add(e);let n=e+1;for(;n<t.length&&!/\/>/.test(t[n]);)s.add(n++);n<t.length&&s.add(n),e=n+1<t.length&&/^\s*\)\s*;?\s*$/.test(t[n+1])?(s.add(n+1),n+2):n+1}else if(/@bind\s*\(/.test(t[e])||/@bind:[A-Za-z_$][\w$]*\s*\(/.test(t[e])||/@field\s*\(/.test(t[e])){e>0&&/<\s*[A-Za-z_]/.test(t[e-1])&&!/>\s*$/.test(t[e-1].trim())&&s.add(e-1),s.add(e);let n=e+1;for(;n<t.length&&!/\/>/.test(t[n]);)s.add(n++);n<t.length&&s.add(n),e=n+1<t.length&&/^\s*\)\s*;?\s*$/.test(t[n+1])?(s.add(n+1),n+2):n+1}else e++;return s}function de(t){let s=new Set;for(let e of t){let n=e.match(/@slot\.\w+\s*\(\s*\{([^}]*)\}\s*\)\s*\{/);if(n)for(let i of n[1].split(",")){let r=i.split(":")[0].trim();/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(r)&&s.add(r)}}return s}function Xe(t){return Ue.test(t)}function ue(t,s){let e=0;for(let n=s;n<t.length;n++)if(e+=Je(t[n]),e<=0){let i=Ye(t,n+1);if(i!==-1&&Be.test(t[i])){e=0,n=i-1;continue}return n}return t.length-1}function Je(t){let s=0,e=!1,n="";for(let i=0;i<t.length;i++){let r=t[i];if(e){if(r==="\\"){i++;continue}r===n&&(e=!1);continue}if(r==="'"||r==='"'||r==="`"){e=!0,n=r;continue}r==="{"&&s++,r==="}"&&s--}return s}function Ye(t,s){for(let e=s;e<t.length;e++)if(t[e].trim())return e;return-1}he.exports={readFileFromDisk:fe,filterDiagnostics:Ge,mapDiagnosticSpans:Ke,buildSuppressedSet:U,extractSlotParamNames:de}});var{DIRECTIVE_RE:He,VIRTUAL_SUFFIX:I}=R(),{stripHelfyDirectivesForParse:ge,buildHelfyPositionMap:Se}=j(),{createVirtualHost:Ne,remapForPosition:Q}=ae(),{readFileFromDisk:et,filterDiagnostics:G,mapDiagnosticSpans:K,buildSuppressedSet:tt}=pe(),y=new Map,v=null;function $e(t,s){var r,l;if(!t||t.__helfyHostWrapped||!s)return;t.__helfyHostWrapped=!0;let e=(r=t.getScriptSnapshot)==null?void 0:r.bind(t),n=(l=t.readFile)==null?void 0:l.bind(t),i=(o,g)=>{if(!g||typeof o!="string"||!o.endsWith(".tsx"))return g;let u=g.getText(0,g.getLength());if(!u.includes("@bind")&&!u.includes("@ref(")&&!u.includes("@field(")&&!u.includes("@slot."))return g;let a=ge(u);return y.set(o,{original:u,transformed:a}),s.ScriptSnapshot.fromString(a)};if(e){let o=g=>i(g,e(g));try{Object.defineProperty(t,"getScriptSnapshot",{value:o,configurable:!0,writable:!0})}catch(g){t.getScriptSnapshot=o}}n&&(t.readFile=(o,g)=>{let u=n(o,g);if(!u||typeof o!="string"||!o.endsWith(".tsx")||!u.includes("@bind")&&!u.includes("@ref(")&&!u.includes("@field(")&&!u.includes("@slot."))return u;let a=ge(u);return y.set(o,{original:u,transformed:a}),a})}function X(t,s){let e=y.get(t);return e?Se(e.original).origToTrans(s):s}function J(t,s,e){let n=y.get(t);if(!n)return{start:s,length:e};let i=Se(n.original),r=i.transToOrig(s),l=i.transToOrig(s+e);return{start:r,length:Math.max(0,l-r)}}function nt(t){let s=t==null?void 0:t.typescript;function e(n){var h,p;v=n.project.projectService.logger,v.info("[helfy-ts-plugin] Loaded"),$e(n.languageServiceHost,s);let i=(p=(h=n.project).getCompilerHost)==null?void 0:p.call(h);i&&i!==n.languageServiceHost&&$e(i,s);let r=n.languageService,l=Object.create(null);for(let c of Object.keys(r)){let d=r[c];l[c]=typeof d=="function"?(...$)=>d.apply(r,$):d}l.getSyntacticDiagnostics=c=>K(c,G(r,c,r.getSyntacticDiagnostics(c)),y),l.getSuggestionDiagnostics=c=>K(c,G(r,c,r.getSuggestionDiagnostics(c)),y);let o=null;if(s)try{o=s.createLanguageService(Ne(n.languageServiceHost,s)),v.info("[helfy-ts-plugin] Virtual LS created")}catch(c){v.info("[helfy-ts-plugin] Virtual LS error: "+c)}l.getSemanticDiagnostics=c=>{if(v&&v.info(`[helfy-ts-plugin] getSemanticDiagnostics: ${c.split(/[\\/]/).pop()}`),o&&c.endsWith(".tsx"))try{let d=et(c);if(d&&(d.includes("@slot.")||d.includes("@bind")||d.includes("@ref(")||d.includes("@field("))){let m=o.getSemanticDiagnostics(c);return v&&v.info(`[helfy-ts-plugin] virtualLS diags for ${c.split(/[\\/]/).pop()}: ${m.length} (codes: ${m.map(b=>b.code).join(",")||"none"})`),m}let S=n.languageServiceHost.getScriptSnapshot(c),x=S?S.getText(0,S.getLength()):"";if(x.includes("@slot.")||x.includes("@bind")||x.includes("@ref(")||x.includes("@field(")){let m=o.getSemanticDiagnostics(c);return v&&v.info(`[helfy-ts-plugin] virtualLS(snap) diags for ${c.split(/[\\/]/).pop()}: ${m.length}`),m}}catch(d){v&&v.info(`[helfy-ts-plugin] virtualLS error: ${d}`)}return K(c,G(r,c,r.getSemanticDiagnostics(c)),y)};let g=null;function u(c,d){var S;let $=(S=c.version)!=null?S:c.fileName;return(!g||g.ver!==$)&&(g={ver:$,set:tt(c.getFullText().split(`
|
|
10
|
-
`))}),g.set.has(d)}function a(c,d){var x;if(!o||!c.endsWith(".tsx"))return!1;let $=(x=r.getProgram())==null?void 0:x.getSourceFile(c);if(!$||!He.test($.getFullText()))return!1;let{line:S}=$.getLineAndCharacterOfPosition(d);return u($,S)}function f(c,d){var S,x;let $=(S=r.getProgram())==null?void 0:S.getSourceFile(c);return $&&(x=Q($,d))!=null?x:d}return l.getCompletionsAtPosition=(c,d,$)=>{var _,C,w;let S=y.has(c),x=S?X(c,d):d;if(!a(c,d)){let E=r.getCompletionsAtPosition(c,x,$);return S&&(E!=null&&E.entries)&&(E.entries=E.entries.map(F=>F.replacementSpan?A(L({},F),{replacementSpan:J(c,F.replacementSpan.start,F.replacementSpan.length)}):F)),E}let m=(_=r.getProgram())==null?void 0:_.getSourceFile(c),b=(C=m==null?void 0:m.getFullText().split(`
|
|
11
|
-
`))!=null?C:[],{line:T}=m?m.getLineAndCharacterOfPosition(d):{line:-1};if(/@for\b/.test((w=b[T])!=null?w:"")){let E=m?Q(m,d):null;if(E===null)return r.getCompletionsAtPosition(c,d,$);try{return o.getCompletionsAtPosition(c+I,E,$)||r.getCompletionsAtPosition(c,d,$)}catch(F){return r.getCompletionsAtPosition(c,d,$)}}try{return o.getCompletionsAtPosition(c+I,d,$)||r.getCompletionsAtPosition(c,d,$)}catch(E){return r.getCompletionsAtPosition(c,d,$)}},l.getSignatureHelpItems=(c,d,$)=>{let S=y.has(c),x=S?X(c,d):d;if(!a(c,d)){let m=r.getSignatureHelpItems(c,x,$);return S&&(m!=null&&m.applicableSpan)&&(m.applicableSpan=J(c,m.applicableSpan.start,m.applicableSpan.length)),m}try{return o.getSignatureHelpItems(c+I,f(c,d),$)||r.getSignatureHelpItems(c,d,$)}catch(m){return r.getSignatureHelpItems(c,d,$)}},l.getQuickInfoAtPosition=(c,d)=>{var T,_,C;let $=y.has(c),S=$?X(c,d):d;if(!a(c,d)){let w=r.getQuickInfoAtPosition(c,S);return $&&(w!=null&&w.textSpan)?A(L({},w),{textSpan:J(c,w.textSpan.start,w.textSpan.length)}):w}let x=(T=r.getProgram())==null?void 0:T.getSourceFile(c),m=(_=x==null?void 0:x.getFullText().split(`
|
|
12
|
-
`))!=null?_:[],{line:b}=x?x.getLineAndCharacterOfPosition(d):{line:-1};if(/@for\b/.test((C=m[b])!=null?C:"")){let w=x?Q(x,d):null;if(w===null)return r.getQuickInfoAtPosition(c,d);try{return o.getQuickInfoAtPosition(c+I,w)||r.getQuickInfoAtPosition(c,d)}catch(E){return r.getQuickInfoAtPosition(c,d)}}try{return o.getQuickInfoAtPosition(c+I,d)||r.getQuickInfoAtPosition(c,d)}catch(w){return r.getQuickInfoAtPosition(c,d)}},l}return{create:e}}module.exports=nt;
|