lcap-frontend-library 0.0.1
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 +271 -0
- package/bin/lcap-frontend-library.mjs +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +27 -0
- package/dist/init.d.ts +6 -0
- package/dist/init.js +79 -0
- package/dist/sync.d.ts +4 -0
- package/dist/sync.js +70 -0
- package/dist/utils.d.ts +19 -0
- package/dist/utils.js +101 -0
- package/package.json +34 -0
- package/packages/lcap-frontend-library/LEARNINGS.md +11 -0
- package/packages/lcap-frontend-library/SKILL.md +86 -0
- package/packages/lcap-frontend-library/commands/migrate.check.md +287 -0
- package/packages/lcap-frontend-library/commands/migrate.green.md +190 -0
- package/packages/lcap-frontend-library/commands/migrate.plan.md +169 -0
- package/packages/lcap-frontend-library/commands/migrate.red.md +160 -0
- package/packages/lcap-frontend-library/commands/migrate.scan.md +151 -0
- package/packages/lcap-frontend-library/commands/migrate.spec.md +144 -0
- package/packages/lcap-frontend-library/commands/migrate.tasks.md +179 -0
- package/packages/lcap-frontend-library/commands/speckit.create.md +201 -0
- package/packages/lcap-frontend-library/commands/speckit.implement.md +88 -0
- package/packages/lcap-frontend-library/commands/speckit.plan.md +79 -0
- package/packages/lcap-frontend-library/commands/speckit.self-check.md +177 -0
- package/packages/lcap-frontend-library/commands/speckit.specify.md +91 -0
- package/packages/lcap-frontend-library/commands/speckit.tasks.md +61 -0
- package/packages/lcap-frontend-library/references/frontend-design/LICENSE.txt +177 -0
- package/packages/lcap-frontend-library/references/frontend-design/SKILL.md +42 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/SKILL.md +360 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/api.md +331 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/block.md +160 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/i18n.md +95 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/icon.md +27 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/container.md +728 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/element.md +312 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/expression.md +154 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/index.md +113 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/modal.md +189 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide/popover.md +171 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/ide.md +799 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/implementation-rules.md +242 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/index.md +27 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/nasl-view-component.md +895 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/accessibility.md +185 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/child.md +82 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/data-source.md +261 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/event.md +171 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/form.md +266 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/function.md +80 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/link.md +137 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/slot.md +128 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-ant-design.md +1470 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-cloud-ui.md +259 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-element-plus.md +580 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-element-ui.md +1007 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/platform/theme-variables-mobile-ui.md +85 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/theme.md +234 -0
- package/packages/lcap-frontend-library/references/lcap-extension-component/workflow-guardrails.md +328 -0
- package/packages/lcap-frontend-library/references/nasl-logic-authoring/SKILL.md +201 -0
- package/packages/lcap-frontend-library/scripts/bash/create-component-files.sh +95 -0
- package/packages/lcap-frontend-library/scripts/bash/create-extension-project.sh +109 -0
- package/packages/lcap-frontend-library/scripts/bash/create-logic-files.sh +149 -0
- package/packages/lcap-frontend-library/scripts/bash/create-spec.sh +109 -0
- package/packages/lcap-frontend-library/scripts/bash/get-available-port.sh +35 -0
- package/packages/lcap-frontend-library/scripts/bash/list-specs.sh +19 -0
- package/packages/lcap-frontend-library/scripts/node/setup-extension-project.mjs +166 -0
- package/packages/lcap-frontend-library/templates/component-self-check.md +31 -0
- package/packages/lcap-frontend-library/templates/component-template.md +96 -0
- package/packages/lcap-frontend-library/templates/library-report-template.md +52 -0
- package/packages/lcap-frontend-library/templates/logic-template.md +44 -0
- package/packages/lcap-frontend-library/templates/migration-manifest-template.md +84 -0
- package/packages/lcap-frontend-library/templates/migration-plan-template.md +138 -0
- package/packages/lcap-frontend-library/templates/migration-report-template.md +227 -0
- package/packages/lcap-frontend-library/templates/migration-spec-template.md +135 -0
- package/packages/lcap-frontend-library/templates/migration-tasks-template.md +129 -0
- package/packages/lcap-frontend-library/templates/plan-template.md +299 -0
- package/packages/lcap-frontend-library/templates/self-check-report-template.md +148 -0
- package/packages/lcap-frontend-library/templates/tasks-template.md +81 -0
- package/packages/lcap-frontend-library/workflows/create/flow.md +199 -0
- package/packages/lcap-frontend-library/workflows/evolve/flow.md +249 -0
- package/packages/lcap-frontend-library/workflows/generate/flow.md +10 -0
- package/packages/lcap-frontend-library/workflows/harness/flow.md +82 -0
- package/packages/lcap-frontend-library/workflows/migrate/flow.md +302 -0
- package/packages/lcap-frontend-library/workflows/migrate/knowledge-base.md +564 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nasl-logic-authoring
|
|
3
|
+
description: >-
|
|
4
|
+
Authors dependency-library logic for LCAP/NASL using @nasl/types, JSDoc
|
|
5
|
+
@NaslLogic metadata, generics, rest parameters, and higher-order function
|
|
6
|
+
signatures; entry at logics/index.ts. Use when writing or refactoring
|
|
7
|
+
NaslLogic, logics/index.ts, nasl.collection types, dependency library TS, or
|
|
8
|
+
platform-exposed functions.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# NASL 依赖库逻辑编写规范
|
|
12
|
+
|
|
13
|
+
## When to apply
|
|
14
|
+
|
|
15
|
+
编写或改造 **依赖库逻辑**、需接入平台的 **`@NaslLogic`** 函数、使用 **`nasl.*` 类型**、**可变参数 / 泛型 / 函数类型入参** 时遵循本文。
|
|
16
|
+
|
|
17
|
+
## 代码位置
|
|
18
|
+
|
|
19
|
+
- **逻辑目录入口**:`logics/index.ts`(在此集中导出需接入平台的逻辑,或 `export * from './xxx'` 聚合子模块)。
|
|
20
|
+
- 具体实现可拆到 `logics/` 下其他文件,但**对外暴露给平台的导出**应与 `logics/index.ts` 的约定一致(以项目规范为准)。
|
|
21
|
+
|
|
22
|
+
## 环境要求(可变参数、泛型、高阶函数相关能力)
|
|
23
|
+
|
|
24
|
+
- IDE **≥ 3.8**
|
|
25
|
+
- Node **≥ 18**
|
|
26
|
+
- lcap **> 0.4.x**
|
|
27
|
+
|
|
28
|
+
## Instructions(Agent 必须遵守)
|
|
29
|
+
|
|
30
|
+
1. **路径**:新增或调整对外逻辑时,以 **`logics/index.ts`** 为入口,与仓库既有 `logics/` 结构保持一致。
|
|
31
|
+
2. 文件顶部 **`import '@nasl/types';`**,参数与返回值用 **`nasl` 命名空间类型** 声明,勿随意用原生 `any` 替代平台语义类型。
|
|
32
|
+
3. 每个需接入平台的导出函数使用 **`/** @NaslLogic ... */`** JSDoc;其余注解用于 IDE/文档展示,与平台绑定一致。
|
|
33
|
+
4. **可变参数**:仅允许**一个** rest,且**必须在参数列表最后**;语义上对应列表,类型多用 `nasl.collection.List<...>`。
|
|
34
|
+
5. **泛型**:`@typeParam` 与 TS 泛型一致;可与可变参数、函数类型参数组合。
|
|
35
|
+
6. **高阶函数**:回调/映射函数类型写在参数或返回值上,并在 `@param` / `@returns` 中说明含义。
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## JSDoc:`@NaslLogic` 与常用标签
|
|
40
|
+
|
|
41
|
+
| 标签 | 作用 |
|
|
42
|
+
|------|------|
|
|
43
|
+
| `@NaslLogic` | 声明该函数需接入平台(必填) |
|
|
44
|
+
| `@type` | 绑定端,如 `pc` / `h5` / `both` |
|
|
45
|
+
| `@title` | 逻辑标题(展示用) |
|
|
46
|
+
| `@description` / `@desc` | 逻辑描述;**优先使用 `@description`**,与历史文档 `@desc` 等价时统一一种即可 |
|
|
47
|
+
| `@typeParam` | 泛型形参说明 |
|
|
48
|
+
| `@param` | 参数说明;**写了参数名则按名称与形参匹配**,否则按**参数顺序(index)**匹配 |
|
|
49
|
+
| `@returns` | 返回值说明 |
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## 基础示例
|
|
54
|
+
|
|
55
|
+
### 泛型:过滤列表中的空值
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import '@nasl/types';
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @NaslLogic
|
|
62
|
+
* @title 过滤列表
|
|
63
|
+
* @description 过滤列表中的 null / 假值
|
|
64
|
+
* @typeParam T 元素类型
|
|
65
|
+
* @param list 列表
|
|
66
|
+
* @returns 过滤后的列表
|
|
67
|
+
*/
|
|
68
|
+
export function filterNull<T>(list: nasl.collection.List<T>): nasl.collection.List<T> {
|
|
69
|
+
return list.filter((n) => !!n);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 异步:并发执行若干任务
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import '@nasl/types';
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @NaslLogic
|
|
80
|
+
* @title 并发执行异步任务
|
|
81
|
+
* @description 按并发上限分批执行无参任务函数,收集结果
|
|
82
|
+
* @param count 最大并发数
|
|
83
|
+
* @param taskList 任务函数列表
|
|
84
|
+
* @returns 各任务返回值按完成批次展开后的列表
|
|
85
|
+
*/
|
|
86
|
+
export async function asyncExecuteTask(
|
|
87
|
+
count: nasl.core.Integer,
|
|
88
|
+
taskList: nasl.collection.List<() => nasl.core.Any>
|
|
89
|
+
): Promise<nasl.collection.List<nasl.core.Any>> {
|
|
90
|
+
const asyncTaskCount = count || 5;
|
|
91
|
+
let waitExecuteTasks = [...taskList];
|
|
92
|
+
const results: nasl.collection.List<nasl.core.Any> = [];
|
|
93
|
+
|
|
94
|
+
while (waitExecuteTasks.length > 0) {
|
|
95
|
+
const executeTasks =
|
|
96
|
+
waitExecuteTasks.length > asyncTaskCount
|
|
97
|
+
? waitExecuteTasks.slice(0, asyncTaskCount)
|
|
98
|
+
: waitExecuteTasks;
|
|
99
|
+
|
|
100
|
+
const batch = await Promise.all(executeTasks.map((fn) => Promise.resolve(fn())));
|
|
101
|
+
results.push(...batch);
|
|
102
|
+
waitExecuteTasks = waitExecuteTasks.slice(executeTasks.length);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return results;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
> 若平台侧需「可变参数」形式传入多个任务函数,可将 `taskList` 改为 rest(见下节),并与 IDE 的「添加可变参数」配合使用。
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## 可变参数(rest)
|
|
114
|
+
|
|
115
|
+
- **本质**:在 NASL/TS 侧按**列表**处理;IDE 中可通过 **「添加可变参数」** 逐个追加实参。
|
|
116
|
+
- **规则**:
|
|
117
|
+
- 可变参数**只能出现一次**;
|
|
118
|
+
- 必须位于**最后一个**形参;
|
|
119
|
+
- 可与泛型、高阶函数类型组合。
|
|
120
|
+
|
|
121
|
+
**示例:字符串拼接**
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import '@nasl/types';
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @NaslLogic
|
|
128
|
+
* @title 字符串拼接
|
|
129
|
+
* @description 可变参数示例:拼接多个字符串
|
|
130
|
+
* @param str 参与拼接的字符串(可变)
|
|
131
|
+
* @returns 拼接结果
|
|
132
|
+
*/
|
|
133
|
+
export function concatenateStrings(
|
|
134
|
+
...args: nasl.collection.List<nasl.core.String>
|
|
135
|
+
): nasl.core.String {
|
|
136
|
+
return args.join('');
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**反例(不合法)**:两个 rest 或 rest 不在最后。
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
// 不合法:两个可变参数
|
|
144
|
+
export function bad(
|
|
145
|
+
...a: nasl.collection.List<nasl.core.String>,
|
|
146
|
+
...b: nasl.collection.List<nasl.core.Integer>
|
|
147
|
+
): nasl.core.String {
|
|
148
|
+
return '';
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## 泛型
|
|
155
|
+
|
|
156
|
+
- 入参、返回值可使用同一泛型形参,便于在 IDE 中选择具体数据结构(如 `List` 元素类型)。
|
|
157
|
+
- 与 **可变参数**、**函数类型** 可组合使用;为每个泛型写清 `@typeParam`。
|
|
158
|
+
|
|
159
|
+
(示例见上文 `filterNull<T>`。)
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 高阶函数(函数类型入参 / 返回值)
|
|
164
|
+
|
|
165
|
+
- 将 **回调、映射、谓词** 等声明为函数类型参数(或返回函数),与普通 `@param` 一样写说明,便于平台生成连线与文档。
|
|
166
|
+
- 可与泛型、可变参数组合;注意 rest 仍须在最后。
|
|
167
|
+
|
|
168
|
+
**示例:列表映射**
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import '@nasl/types';
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @NaslLogic
|
|
175
|
+
* @title 列表映射
|
|
176
|
+
* @description 对列表中每个元素应用映射函数
|
|
177
|
+
* @typeParam T 源元素类型
|
|
178
|
+
* @typeParam U 目标元素类型
|
|
179
|
+
* @param list 源列表
|
|
180
|
+
* @param mapper 将 T 转为 U 的函数
|
|
181
|
+
* @returns 新列表
|
|
182
|
+
*/
|
|
183
|
+
export function mapList<T, U>(
|
|
184
|
+
list: nasl.collection.List<T>,
|
|
185
|
+
mapper: (item: T) => U
|
|
186
|
+
): nasl.collection.List<U> {
|
|
187
|
+
return list.map(mapper);
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## 自检清单
|
|
194
|
+
|
|
195
|
+
- [ ] 对外逻辑已从 **`logics/index.ts`**(或经其 re-export)暴露
|
|
196
|
+
- [ ] 已 `import '@nasl/types'`
|
|
197
|
+
- [ ] 公开给平台的函数带 `@NaslLogic` 及 `@title`、参数/返回值说明
|
|
198
|
+
- [ ] 类型以 `nasl.*` 为主,与平台数据结构一致
|
|
199
|
+
- [ ] 使用可变参数时:仅一处 rest,且在最后
|
|
200
|
+
- [ ] 泛型已用 `@typeParam` 说明
|
|
201
|
+
- [ ] 函数类型参数在 `@param` 中描述清用途
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 创建组件文件
|
|
3
|
+
# 用法: create-component-files.sh --library-dir <库根> --name <组件名> --title <中文名> [--type pc|h5|both]
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
LIBRARY_DIR=""
|
|
8
|
+
NAME=""
|
|
9
|
+
TITLE=""
|
|
10
|
+
TYPE="pc"
|
|
11
|
+
|
|
12
|
+
usage() {
|
|
13
|
+
echo "用法: $0 --library-dir <库根绝对路径> --name <组件名> --title <中文名> [--type pc|h5|both]" >&2
|
|
14
|
+
echo "组件名仅允许小写字母与下划线" >&2
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
while [[ $# -gt 0 ]]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--library-dir)
|
|
20
|
+
LIBRARY_DIR="$2"
|
|
21
|
+
shift 2
|
|
22
|
+
;;
|
|
23
|
+
--name)
|
|
24
|
+
NAME="$2"
|
|
25
|
+
shift 2
|
|
26
|
+
;;
|
|
27
|
+
--title)
|
|
28
|
+
TITLE="$2"
|
|
29
|
+
shift 2
|
|
30
|
+
;;
|
|
31
|
+
--type)
|
|
32
|
+
TYPE="$2"
|
|
33
|
+
shift 2
|
|
34
|
+
;;
|
|
35
|
+
-h|--help)
|
|
36
|
+
usage
|
|
37
|
+
exit 0
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
echo "错误:未知参数 $1" >&2
|
|
41
|
+
usage
|
|
42
|
+
exit 1
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
if [ -z "$LIBRARY_DIR" ] || [ -z "$NAME" ] || [ -z "$TITLE" ]; then
|
|
48
|
+
echo "错误:缺少 --library-dir、--name 或 --title" >&2
|
|
49
|
+
usage
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if ! [[ "$NAME" =~ ^[a-z_]+$ ]]; then
|
|
54
|
+
echo "错误:组件名仅允许小写字母与下划线,当前值: $NAME" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
case "$TYPE" in
|
|
59
|
+
pc|h5|both) ;;
|
|
60
|
+
*)
|
|
61
|
+
echo "错误:--type 必须为 pc、h5 或 both,当前值: $TYPE" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
if [ ! -d "$LIBRARY_DIR" ]; then
|
|
67
|
+
echo "错误:库目录不存在: $LIBRARY_DIR" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
LIBRARY_DIR="$(cd "$LIBRARY_DIR" && pwd)"
|
|
72
|
+
|
|
73
|
+
if [ ! -f "$LIBRARY_DIR/package.json" ]; then
|
|
74
|
+
echo "错误:未找到 package.json: $LIBRARY_DIR/package.json" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if ! (cd "$LIBRARY_DIR" && node -e "
|
|
79
|
+
const fs = require('fs');
|
|
80
|
+
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
81
|
+
const deps = { ...p.dependencies, ...p.devDependencies };
|
|
82
|
+
process.exit(deps['@lcap/builder'] ? 0 : 1);
|
|
83
|
+
"); then
|
|
84
|
+
echo "错误:package.json 中未找到 @lcap/builder" >&2
|
|
85
|
+
exit 1
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [ ! -d "$LIBRARY_DIR/node_modules/@lcap/builder" ]; then
|
|
89
|
+
echo "错误:未安装依赖,请执行: npm install --prefix \"$LIBRARY_DIR\"" >&2
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
prompt_json="$(node -e "console.log(JSON.stringify({ name: process.argv[1], title: process.argv[2], type: process.argv[3] }))" "$NAME" "$TITLE" "$TYPE")"
|
|
94
|
+
|
|
95
|
+
(cd "$LIBRARY_DIR" && npx lcap-scripts create --component --prompt "$prompt_json")
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 创建扩展依赖库工程
|
|
3
|
+
# 用法: create-extension-project.sh --name <库名> --title <中文标题> --target-dir <放置目录> [--template vue3|vue2]
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
8
|
+
|
|
9
|
+
NAME=""
|
|
10
|
+
TITLE=""
|
|
11
|
+
TARGET_DIR=""
|
|
12
|
+
TEMPLATE="vue3"
|
|
13
|
+
|
|
14
|
+
usage() {
|
|
15
|
+
echo "用法: $0 --name <库名> --title <中文标题> --target-dir <放置目录> [--template vue3|vue2]" >&2
|
|
16
|
+
echo "库名仅允许小写字母与下划线" >&2
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
while [[ $# -gt 0 ]]; do
|
|
20
|
+
case "$1" in
|
|
21
|
+
--name)
|
|
22
|
+
NAME="$2"
|
|
23
|
+
shift 2
|
|
24
|
+
;;
|
|
25
|
+
--title)
|
|
26
|
+
TITLE="$2"
|
|
27
|
+
shift 2
|
|
28
|
+
;;
|
|
29
|
+
--target-dir)
|
|
30
|
+
TARGET_DIR="$2"
|
|
31
|
+
shift 2
|
|
32
|
+
;;
|
|
33
|
+
--template)
|
|
34
|
+
TEMPLATE="$2"
|
|
35
|
+
shift 2
|
|
36
|
+
;;
|
|
37
|
+
-h|--help)
|
|
38
|
+
usage
|
|
39
|
+
exit 0
|
|
40
|
+
;;
|
|
41
|
+
*)
|
|
42
|
+
echo "错误:未知参数 $1" >&2
|
|
43
|
+
usage
|
|
44
|
+
exit 1
|
|
45
|
+
;;
|
|
46
|
+
esac
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
if [ -z "$NAME" ] || [ -z "$TITLE" ]; then
|
|
50
|
+
echo "错误:缺少 --name 或 --title" >&2
|
|
51
|
+
usage
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [ -z "$TARGET_DIR" ]; then
|
|
56
|
+
echo "错误:缺少 --target-dir 参数" >&2
|
|
57
|
+
usage
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
if ! [[ "$NAME" =~ ^[a-z_]+$ ]]; then
|
|
62
|
+
echo "错误:库名仅允许小写字母与下划线,当前值: $NAME" >&2
|
|
63
|
+
exit 1
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
case "$TEMPLATE" in
|
|
67
|
+
vue2|vue3) ;;
|
|
68
|
+
react)
|
|
69
|
+
echo "错误:暂不支持 react 建库,请使用 --template vue2 或 vue3" >&2
|
|
70
|
+
exit 1
|
|
71
|
+
;;
|
|
72
|
+
*)
|
|
73
|
+
echo "错误:--template 必须为 vue2 或 vue3,当前值: $TEMPLATE" >&2
|
|
74
|
+
exit 1
|
|
75
|
+
;;
|
|
76
|
+
esac
|
|
77
|
+
|
|
78
|
+
mkdir -p "$TARGET_DIR"
|
|
79
|
+
TARGET_DIR_ABS="$(cd "$TARGET_DIR" && pwd)"
|
|
80
|
+
|
|
81
|
+
prompt_json="$(node -e "
|
|
82
|
+
console.log(JSON.stringify({
|
|
83
|
+
packageName: process.argv[1],
|
|
84
|
+
title: process.argv[2],
|
|
85
|
+
template: process.argv[3],
|
|
86
|
+
}));
|
|
87
|
+
" "$NAME" "$TITLE" "$TEMPLATE")"
|
|
88
|
+
|
|
89
|
+
(
|
|
90
|
+
cd "$TARGET_DIR_ABS"
|
|
91
|
+
npm create lcap-extension@latest -- --name "$NAME" --prompt "$prompt_json"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
LIBRARY_DIR="$TARGET_DIR_ABS/$NAME"
|
|
95
|
+
if [ ! -f "$LIBRARY_DIR/package.json" ]; then
|
|
96
|
+
echo "错误:未找到新建工程:$LIBRARY_DIR/package.json" >&2
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
SETUP_JS="${SCRIPT_DIR}/../node/setup-extension-project.mjs"
|
|
101
|
+
if [ ! -f "$SETUP_JS" ]; then
|
|
102
|
+
echo "错误:未找到 setup-extension-project.mjs:$SETUP_JS" >&2
|
|
103
|
+
exit 1
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
node "$SETUP_JS" "$LIBRARY_DIR"
|
|
107
|
+
|
|
108
|
+
echo "libraryDir=$LIBRARY_DIR"
|
|
109
|
+
echo "template=$TEMPLATE"
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 创建逻辑函数文件
|
|
3
|
+
# 用法: create-logic-files.sh --library-dir <库根> --name <函数名 snake_case> --title <逻辑中文标题> [--type pc|h5|both]
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
LIBRARY_DIR=""
|
|
8
|
+
NAME=""
|
|
9
|
+
TITLE=""
|
|
10
|
+
TYPE="pc"
|
|
11
|
+
|
|
12
|
+
usage() {
|
|
13
|
+
echo "用法: $0 --library-dir <库根> --name <函数名 snake_case> --title <逻辑中文标题> [--type pc|h5|both]" >&2
|
|
14
|
+
echo "函数名仅允许小写字母与下划线" >&2
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
while [[ $# -gt 0 ]]; do
|
|
18
|
+
case "$1" in
|
|
19
|
+
--library-dir)
|
|
20
|
+
LIBRARY_DIR="$2"
|
|
21
|
+
shift 2
|
|
22
|
+
;;
|
|
23
|
+
--name)
|
|
24
|
+
NAME="$2"
|
|
25
|
+
shift 2
|
|
26
|
+
;;
|
|
27
|
+
--title)
|
|
28
|
+
TITLE="$2"
|
|
29
|
+
shift 2
|
|
30
|
+
;;
|
|
31
|
+
--type)
|
|
32
|
+
TYPE="$2"
|
|
33
|
+
shift 2
|
|
34
|
+
;;
|
|
35
|
+
-h|--help)
|
|
36
|
+
usage
|
|
37
|
+
exit 0
|
|
38
|
+
;;
|
|
39
|
+
*)
|
|
40
|
+
echo "错误:未知参数 $1" >&2
|
|
41
|
+
usage
|
|
42
|
+
exit 1
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
if [ -z "$LIBRARY_DIR" ] || [ -z "$NAME" ] || [ -z "$TITLE" ]; then
|
|
48
|
+
echo "错误:缺少 --library-dir、--name 或 --title" >&2
|
|
49
|
+
usage
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if ! [[ "$NAME" =~ ^[a-z_]+$ ]]; then
|
|
54
|
+
echo "错误:函数名仅允许小写字母与下划线,当前值: $NAME" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
case "$TYPE" in
|
|
59
|
+
pc|h5|both) ;;
|
|
60
|
+
*)
|
|
61
|
+
echo "错误:--type 必须为 pc、h5 或 both,当前值: $TYPE" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
;;
|
|
64
|
+
esac
|
|
65
|
+
|
|
66
|
+
if [ ! -d "$LIBRARY_DIR" ]; then
|
|
67
|
+
echo "错误:库目录不存在: $LIBRARY_DIR" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
LIBRARY_DIR="$(cd "$LIBRARY_DIR" && pwd)"
|
|
72
|
+
|
|
73
|
+
if [ ! -f "$LIBRARY_DIR/package.json" ]; then
|
|
74
|
+
echo "错误:未找到 package.json: $LIBRARY_DIR/package.json" >&2
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
if ! (cd "$LIBRARY_DIR" && node -e "
|
|
79
|
+
const fs = require('fs');
|
|
80
|
+
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
81
|
+
const deps = { ...p.dependencies, ...p.devDependencies };
|
|
82
|
+
process.exit(deps['@lcap/builder'] ? 0 : 1);
|
|
83
|
+
"); then
|
|
84
|
+
echo "错误:package.json 中未找到 @lcap/builder" >&2
|
|
85
|
+
exit 1
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [ ! -d "$LIBRARY_DIR/node_modules/@lcap/builder" ]; then
|
|
89
|
+
echo "错误:未安装依赖,请执行: npm install --prefix \"$LIBRARY_DIR\"" >&2
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
CAMEL_NAME=$(node -e "
|
|
94
|
+
const name = process.argv[1];
|
|
95
|
+
const camel = name.replace(/_([a-z])/g, (_, c) => c.toUpperCase());
|
|
96
|
+
console.log(camel);
|
|
97
|
+
" "$NAME")
|
|
98
|
+
|
|
99
|
+
LOGIC_DIR="$LIBRARY_DIR/src/logics"
|
|
100
|
+
LOGIC_FILE="$LOGIC_DIR/$NAME.ts"
|
|
101
|
+
INDEX_FILE="$LOGIC_DIR/index.ts"
|
|
102
|
+
TEST_FILE="$LOGIC_DIR/__tests__/$NAME.spec.ts"
|
|
103
|
+
|
|
104
|
+
if [ -f "$LOGIC_FILE" ]; then
|
|
105
|
+
echo "错误:逻辑文件已存在: $LOGIC_FILE" >&2
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
mkdir -p "$LOGIC_DIR"
|
|
110
|
+
mkdir -p "$LOGIC_DIR/__tests__"
|
|
111
|
+
|
|
112
|
+
cat > "$LOGIC_FILE" <<EOF
|
|
113
|
+
import '@nasl/types';
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @NaslLogic
|
|
117
|
+
* @title $TITLE
|
|
118
|
+
* @description TODO
|
|
119
|
+
* @type $TYPE
|
|
120
|
+
*/
|
|
121
|
+
export function $CAMEL_NAME() {
|
|
122
|
+
// TODO
|
|
123
|
+
}
|
|
124
|
+
EOF
|
|
125
|
+
|
|
126
|
+
if [ ! -f "$INDEX_FILE" ]; then
|
|
127
|
+
touch "$INDEX_FILE"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
EXPORT_LINE="export { $CAMEL_NAME } from './$NAME';"
|
|
131
|
+
if ! grep -qF "$EXPORT_LINE" "$INDEX_FILE" 2>/dev/null; then
|
|
132
|
+
echo "$EXPORT_LINE" >> "$INDEX_FILE"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
cat > "$TEST_FILE" <<EOF
|
|
136
|
+
import { describe, it } from 'vitest';
|
|
137
|
+
import { $CAMEL_NAME } from '../$NAME';
|
|
138
|
+
|
|
139
|
+
describe('$CAMEL_NAME', () => {
|
|
140
|
+
it('TODO', () => {
|
|
141
|
+
// TODO
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
EOF
|
|
145
|
+
|
|
146
|
+
echo "已创建逻辑文件:"
|
|
147
|
+
echo " $LOGIC_FILE"
|
|
148
|
+
echo " $INDEX_FILE (已追加导出)"
|
|
149
|
+
echo " $TEST_FILE"
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 创建规范需求目录(Spec Driven Development)
|
|
3
|
+
# 用法:
|
|
4
|
+
# 普通: bash create-spec.sh --short-name "name"
|
|
5
|
+
# 供 speckit.specify 调用: bash create-spec.sh --json --short-name "name"
|
|
6
|
+
# 注意:必须在 LCAP 扩展工程目录内执行(即 cwd 为工程根目录),specs 将创建在 cwd/specs/ 下
|
|
7
|
+
# 目录名称: kebab-case,2-4 个英文词,例如 my-feature、user-auth-api
|
|
8
|
+
|
|
9
|
+
set -e
|
|
10
|
+
|
|
11
|
+
# 解析参数
|
|
12
|
+
JSON_MODE=false
|
|
13
|
+
SHORT_NAME=""
|
|
14
|
+
SPECS_DIR_ARG=""
|
|
15
|
+
while [[ $# -gt 0 ]]; do
|
|
16
|
+
case "$1" in
|
|
17
|
+
--json)
|
|
18
|
+
JSON_MODE=true
|
|
19
|
+
shift
|
|
20
|
+
;;
|
|
21
|
+
--short-name)
|
|
22
|
+
SHORT_NAME="$2"
|
|
23
|
+
shift 2
|
|
24
|
+
;;
|
|
25
|
+
--specs-dir)
|
|
26
|
+
SPECS_DIR_ARG="$2"
|
|
27
|
+
shift 2
|
|
28
|
+
;;
|
|
29
|
+
-ShortName)
|
|
30
|
+
# PowerShell 风格
|
|
31
|
+
SHORT_NAME="$2"
|
|
32
|
+
shift 2
|
|
33
|
+
;;
|
|
34
|
+
*)
|
|
35
|
+
if [ "$JSON_MODE" = false ] && [ -z "$SHORT_NAME" ] && [[ "$1" != --* ]]; then
|
|
36
|
+
SHORT_NAME="$1"
|
|
37
|
+
fi
|
|
38
|
+
shift
|
|
39
|
+
;;
|
|
40
|
+
esac
|
|
41
|
+
done
|
|
42
|
+
|
|
43
|
+
current_dir=$(pwd)
|
|
44
|
+
|
|
45
|
+
# 确认当前工作目录为 LCAP 扩展工程(与 create-component-files.sh 一致)
|
|
46
|
+
if [ ! -f package.json ]; then
|
|
47
|
+
echo "错误:当前目录下没有 package.json,请先 cd 到 LCAP 扩展工程目录再执行本脚本。" >&2
|
|
48
|
+
echo "当前目录: $current_dir" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
if ! node -e "
|
|
53
|
+
const fs = require('fs');
|
|
54
|
+
const p = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
55
|
+
const deps = { ...p.dependencies, ...p.devDependencies };
|
|
56
|
+
process.exit(deps['@lcap/builder'] ? 0 : 1);
|
|
57
|
+
" 2>/dev/null; then
|
|
58
|
+
echo "错误:package.json 中未找到 @lcap/builder 依赖,请确认当前目录为 LCAP 扩展组件工程。" >&2
|
|
59
|
+
echo "当前目录: $current_dir" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# specs 目录优先级:--specs-dir 参数 > SPECS_DIR 环境变量 > cwd/specs
|
|
64
|
+
specs_dir="${SPECS_DIR_ARG:-${SPECS_DIR:-$current_dir/specs}}"
|
|
65
|
+
|
|
66
|
+
if [ -z "$SHORT_NAME" ]; then
|
|
67
|
+
if [ "$JSON_MODE" = true ]; then
|
|
68
|
+
echo '{"error":"缺少 --short-name 参数"}' >&2
|
|
69
|
+
exit 1
|
|
70
|
+
fi
|
|
71
|
+
echo "错误:请输入规范需求目录名称(kebab-case,2-4 个英文词)"
|
|
72
|
+
echo "用法: $0 [--json] --short-name \"名称\""
|
|
73
|
+
echo "注意:必须在 LCAP 扩展工程目录内执行"
|
|
74
|
+
exit 1
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
name="$SHORT_NAME"
|
|
78
|
+
|
|
79
|
+
# 计算下一个序号
|
|
80
|
+
highest=0
|
|
81
|
+
if [ -d "$specs_dir" ]; then
|
|
82
|
+
for dir in "$specs_dir"/*; do
|
|
83
|
+
[ -d "$dir" ] || continue
|
|
84
|
+
dirname=$(basename "$dir")
|
|
85
|
+
number=$(echo "$dirname" | grep -o '^[0-9]\+' || echo "0")
|
|
86
|
+
number=$((10#$number))
|
|
87
|
+
if [ "$number" -gt "$highest" ]; then highest=$number; fi
|
|
88
|
+
done
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
next=$((highest + 1))
|
|
92
|
+
feature_number=$(printf "%02d" "$next")
|
|
93
|
+
current_spec_dir="$specs_dir/$feature_number-$name"
|
|
94
|
+
|
|
95
|
+
# 创建目录与空 spec.md
|
|
96
|
+
mkdir -p "$current_spec_dir"
|
|
97
|
+
touch "$current_spec_dir/spec.md"
|
|
98
|
+
|
|
99
|
+
# 转为绝对路径
|
|
100
|
+
current_spec_dir_abs=$(cd "$current_spec_dir" && pwd)
|
|
101
|
+
spec_file_abs="$current_spec_dir_abs/spec.md"
|
|
102
|
+
feature_dir_abs="$current_spec_dir_abs"
|
|
103
|
+
|
|
104
|
+
if [ "$JSON_MODE" = true ]; then
|
|
105
|
+
echo "{\"SPEC_FILE\":\"$spec_file_abs\",\"FEATURE_DIR\":\"$feature_dir_abs\"}"
|
|
106
|
+
else
|
|
107
|
+
echo "规范需求目录已创建:$current_spec_dir_abs"
|
|
108
|
+
echo " - spec.md"
|
|
109
|
+
fi
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 获取可用端口号(49152-65535 动态端口范围)
|
|
3
|
+
# 用法: .specify/scripts/bash/get-available-port.sh
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
MIN_PORT=49152
|
|
8
|
+
MAX_PORT=65535
|
|
9
|
+
RANGE=$((MAX_PORT - MIN_PORT + 1))
|
|
10
|
+
|
|
11
|
+
# 尝试最多 100 次找到可用端口
|
|
12
|
+
for _ in $(seq 1 100); do
|
|
13
|
+
# 生成随机端口
|
|
14
|
+
port=$((MIN_PORT + RANDOM % RANGE))
|
|
15
|
+
|
|
16
|
+
# 检查端口是否可用(nc -z 连接成功返回 0,即端口被占用)
|
|
17
|
+
if command -v nc &>/dev/null; then
|
|
18
|
+
if ! nc -z 127.0.0.1 "$port" 2>/dev/null; then
|
|
19
|
+
echo "$port"
|
|
20
|
+
exit 0
|
|
21
|
+
fi
|
|
22
|
+
elif command -v lsof &>/dev/null; then
|
|
23
|
+
if ! lsof -i ":$port" &>/dev/null; then
|
|
24
|
+
echo "$port"
|
|
25
|
+
exit 0
|
|
26
|
+
fi
|
|
27
|
+
else
|
|
28
|
+
# 无 nc/lsof 时直接返回随机端口(可能被占用,调用方需自行处理)
|
|
29
|
+
echo "$port"
|
|
30
|
+
exit 0
|
|
31
|
+
fi
|
|
32
|
+
done
|
|
33
|
+
|
|
34
|
+
echo "错误:无法在 $MIN_PORT-$MAX_PORT 范围内找到可用端口" >&2
|
|
35
|
+
exit 1
|