This commit is contained in:
2026-05-26 20:51:20 +08:00
2827 changed files with 28013 additions and 442469 deletions
+110
View File
@@ -0,0 +1,110 @@
# Skill: 生成模块设计总览页
## 触发方式
用户说"生成设计总览"、"design overview"或指定某个模块需要生成设计总览时触发。
## 输入参数
- **模块路径**(必须):如 `employee-app/emergency-medical`
- **模块中文名**(必须):如 `应急就医员工端APP`
## 执行流程
### Step 1: 扫描模块页面结构
1. 列出模块目录下所有 `.html` 文件
2. 逐个读取每个 HTML 文件,识别:
- 页面标题和主要内容
- 弹窗/对话框(`display:none` 的 modal、mask、overlay、panel 等)
- Tab 切换 / 状态切换(语音/文字模式、展开/收起等)
- 触发弹窗的 CSS 类名和切换方式
3. 读取 `doc/PRD.md`(如存在),获取业务主线分组
### Step 2: 整理页面形态清单 & 复用已有截图
1. 检查 `doc/screenshots/` 目录下已有的截图文件
2. 将已有截图与页面一一对应(按文件名匹配)
3. 标记出缺失的弹窗/状态截图(仅这些需要新截取)
4. **已有截图直接复用,不重新截取**
### Step 3: 截取缺失的弹窗截图
**截图工具优先级**(按可用性依次尝试):
1. **agent-browser**(首选):原生 Rust CLI,截图质量最好
2. **chrome-devtools MCP**(备选):通过 MCP 协议控制 Chrome
3. **Puppeteer 脚本**(兜底):使用 `_templates/screenshot-modals.js`
#### 使用 agent-browser 截图:
```bash
agent-browser open "file:///<绝对路径>/<页面>.html"
agent-browser set viewport 390 844 2
# 触发弹窗状态
agent-browser snapshot -i # 获取元素 ref
agent-browser click @eN # 或用 evaluate 执行 JS
agent-browser screenshot "<输出路径>.jpg"
agent-browser close
```
#### 使用 Puppeteer 脚本截图(兜底方案):
编写 config.json 配置文件,只包含缺失的截图任务:
```json
{
"baseDir": "<模块路径>",
"tasks": [
{ "page": "xxx.html", "output": "xxx-modal.jpg",
"action": "() => { /* 触发弹窗的JS */ }" }
]
}
```
运行:`node _templates/screenshot-modals.js <config.json>`
**关键参数**Puppeteer):
```javascript
// 视口必须大于 phone-shell 尺寸(390px宽),避免布局溢出
page.setViewport({ width: 500, height: 900, deviceScaleFactor: 1 });
// 只截取 .phone-shell 元素,避免外壳嵌套感
const shell = await page.$('.phone-shell');
if (shell) await shell.screenshot({ path, type: 'jpeg', quality: 85 });
```
**截图规范(参考项目背景.md 7.4 节)**
- 输出格式:JPEG,质量 85%(兼顾清晰度与文件体积)
- deviceScaleFactor 设为 1(设计总览卡片仅 260px 宽,不需要 2x 分辨率)
- 单张截图体积控制在 **60KB 以内**,避免项目膨胀
- 视口宽度 500px(大于 phone-shell 的 390px 避免溢出),高度 900px
- 只截取 `.phone-shell` 元素的可视区域(不展开滚动内容),保持手机屏幕视角
- 截图命名规范:`{页面名}-{状态}.jpg`,如 `emergency-chat-confirm.jpg`
- 常规页面截图命名与 HTML 文件名一致(去掉 `.html`),如 `index.jpg`
### Step 4: 生成 design-overview.html
使用 `_templates/design-overview-template.html` 模板,填充:
- 导航标题:`{模块中文名} · 设计总览`
- 各业务主线 sectionid 为 `sec-{英文缩写}`
- 每张截图一个 card,包含图片、标签名、弹窗/状态标记
- **截图路径必须与 `doc/screenshots/` 下的实际文件名一致**
**样式规范(必须与模板一致)**
- 暗色背景 `#1a1a2e`
- 卡片尺寸 `260×564px`(手机比例 375:812 的 ~70%
- 每条业务线横向滚动不换行(`overflow-x: auto`
- 弹窗标记用橙色 tag `tag--modal`
- 状态切换标记用蓝色 tag `tag--state`
- 点击图片灯箱放大查看
### Step 5: 注册到导航页
在根目录 `index.html``SITE_MAP` 中,找到对应模块的 `pages` 数组,在第一个位置插入:
```javascript
{ file:'../doc/design-overview.html', label:'页面总览' },
```
## 输出物
1. `{模块目录}/doc/design-overview.html` — 设计总览页
2. `{模块目录}/doc/screenshots/*-{状态}.jpg` — 新截取的弹窗截图(仅缺失部分)
3.`index.html` SITE_MAP 更新
## 注意事项
- **复用优先**:已有截图绝不重新截取,只补拍缺失的弹窗/状态截图
- 截图脚本 `_templates/screenshot-modals.js` 放在 _templates 目录,每个模块复用
- Puppeteer 视口必须设为 `500x900`(大于 phone-shell 的 390px),避免"空白页嵌套小页面"问题
- 截图只截取 `.phone-shell` 元素,不截整个页面
- 所有模块的 design-overview 共用同一套 CSS 样式(从模板复制)
- 不要遗漏任何页面形态(弹窗、Tab 状态、展开/收起等)
- 截图配置 json 文件用完后保留在项目根目录,方便后续重新截取
+82
View File
@@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{MODULE_NAME}} - 页面设计总览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #e0e0e0; }
/* 顶部导航 */
.nav { position: sticky; top: 0; z-index: 100; background: #16213e; border-bottom: 1px solid #0f3460; padding: 14px 24px; display: flex; gap: 12px; align-items: center; }
.nav__title { font-size: 16px; font-weight: 600; color: #4fc3f7; margin-right: 20px; white-space: nowrap; }
.nav__link { font-size: 13px; color: #aaa; text-decoration: none; padding: 5px 12px; border-radius: 20px; transition: all .2s; white-space: nowrap; border: 1px solid transparent; }
.nav__link:hover { background: #0f3460; color: #4fc3f7; border-color: #4fc3f7; }
/* 业务主线区块 */
.section { padding: 24px 24px 8px; }
.section__header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.section__title { font-size: 15px; font-weight: 600; color: #fff; }
.section__count { font-size: 12px; color: #666; background: #2a2a4a; padding: 2px 8px; border-radius: 10px; }
/* 横向滚动容器 */
.scroll-row { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 16px; scrollbar-width: thin; scrollbar-color: #333 transparent; }
.scroll-row::-webkit-scrollbar { height: 6px; }
.scroll-row::-webkit-scrollbar-track { background: transparent; }
.scroll-row::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
/* 卡片 */
.card { flex-shrink: 0; width: 260px; cursor: pointer; transition: transform .2s; }
.card:hover { transform: scale(1.02); }
.card__img { width: 260px; height: 564px; border-radius: 12px; overflow: hidden; border: 2px solid #2a2a4a; background: #111; transition: border-color .2s; }
.card:hover .card__img { border-color: #4fc3f7; }
.card__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.card__label { margin-top: 8px; font-size: 12px; color: #999; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card__tags { display: flex; justify-content: center; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.tag { font-size: 10px; padding: 1px 5px; border-radius: 3px; }
.tag--modal { background: #4a2800; color: #ffa940; }
.tag--state { background: #002a4a; color: #4fc3f7; }
/* 分隔线 */
.divider { height: 1px; background: #2a2a4a; margin: 8px 24px; }
/* 灯箱 */
.lightbox { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.92); align-items: center; justify-content: center; cursor: zoom-out; }
.lightbox.show { display: flex; }
.lightbox img { max-width: 90vw; max-height: 92vh; border-radius: 8px; }
.lightbox__close { position: absolute; top: 16px; right: 20px; color: #fff; font-size: 24px; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255,255,255,0.1); }
.lightbox__name { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: #ccc; font-size: 13px; background: rgba(0,0,0,0.6); padding: 6px 16px; border-radius: 20px; }
</style>
</head>
<body>
<!-- 顶部导航 -->
<nav class="nav">
<span class="nav__title">{{MODULE_NAME}} · 设计总览</span>
<!-- {{NAV_LINKS}} -->
</nav>
<!-- {{SECTIONS}} -->
<div style="height:40px;"></div>
<!-- 灯箱 -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<span class="lightbox__close">&times;</span>
<img id="lightbox-img" src="" alt="">
<div class="lightbox__name" id="lightbox-name"></div>
</div>
<script>
function openLightbox(src, name) {
document.getElementById('lightbox-img').src = src;
document.getElementById('lightbox-name').textContent = name;
document.getElementById('lightbox').classList.add('show');
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('show');
}
</script>
</body>
</html>
@@ -3,6 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<base href="../">
<title>文档预览</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
+105
View File
@@ -0,0 +1,105 @@
/**
* 通用弹窗/状态截图脚本
*
* 使用方式:
* node screenshot-modals.js <config.json>
*
* config.json 格式:
* {
* "baseDir": "employee-app/emergency-medical",
* "tasks": [
* { "page": "resource-map.html", "output": "resource-map-simulate.jpg",
* "action": "() => { document.querySelector('.simulate-panel').style.display = 'block'; }" },
* { "page": "detail.html", "output": "detail-full.jpg", "fullPage": true }
* ]
* }
*
* task 字段说明:
* page - 页面 HTML 文件路径(相对于 baseDir
* output - 输出截图文件名
* action - 可选,截图前执行的 JS(触发弹窗/状态)
* fullPage - 可选,true 时去掉 phone-shell 高度限制,截取完整滚动内容(长图)
*
* 如果不传 config.json,则使用内置的应急就医模块配置作为示例。
*/
const puppeteer = require('puppeteer');
const path = require('path');
const fs = require('fs');
const delay = ms => new Promise(r => setTimeout(r, ms));
// 只截取 .phone-shell 元素,避免外壳背景
// fullPage=true 时去掉高度限制和溢出裁剪,截取完整内容(长图)
async function screenshotPhoneShell(page, filepath, fullPage) {
if (fullPage) {
await page.evaluate(() => {
const shell = document.querySelector('.phone-shell');
if (shell) { shell.style.height = 'auto'; shell.style.borderRadius = '0'; }
const sc = document.querySelector('.scroll-content');
if (sc) { sc.style.overflow = 'visible'; sc.style.flex = 'none'; }
});
await new Promise(r => setTimeout(r, 100));
}
const shell = await page.$('.phone-shell');
if (shell) {
await shell.screenshot({ path: filepath, type: 'jpeg', quality: 85 });
} else {
await page.screenshot({ path: filepath, type: 'jpeg', quality: 85 });
}
}
// 默认配置(应急就医模块示例)
const DEFAULT_CONFIG = {
baseDir: 'employee-app/emergency-medical',
tasks: [
{ page: 'resource-map.html', output: 'resource-map-simulate.jpg',
action: `() => { const p = document.querySelector('.simulate-panel'); if(p) p.style.display = 'block'; }` },
{ page: 'emergency-chat.html', output: 'emergency-chat-modal.jpg',
action: `() => { const m = document.querySelector('.modal-overlay'); if(m){m.style.display='flex';m.classList.add('show');} }` },
{ page: 'emergency-chat.html', output: 'emergency-chat-voice.jpg',
action: `() => { const btns = document.querySelectorAll('[class*="voice"]'); btns.forEach(b => b.click()); }` },
{ page: 'emergency-chat.html', output: 'emergency-chat-plus.jpg',
action: `() => { const p = document.querySelector('.plus-panel'); if(p){p.style.display='grid';p.classList.add('show');} }` },
{ page: 'appointment-detail-pending.html', output: 'appointment-detail-pending-modal.jpg',
action: `() => { const m = document.querySelector('.modal-mask'); if(m){m.style.display='flex';m.classList.add('modal-mask--show');} }` },
{ page: 'appointment-detail-confirmed.html', output: 'appointment-detail-confirmed-modal.jpg',
action: `() => { const m = document.querySelector('.modal-mask'); if(m){m.style.display='flex';m.classList.add('modal-mask--show');} }` }
]
};
(async () => {
// 读取配置
let config = DEFAULT_CONFIG;
const configArg = process.argv[2];
if (configArg && fs.existsSync(configArg)) {
config = JSON.parse(fs.readFileSync(configArg, 'utf-8'));
console.log(`Using config: ${configArg}`);
} else {
console.log('Using default config (emergency-medical)');
}
const baseDir = path.resolve(config.baseDir);
const baseUrl = 'file:///' + baseDir.replace(/\\/g, '/');
const outDir = path.join(baseDir, 'doc', 'screenshots');
// 确保输出目录存在
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox'] });
const page = await browser.newPage();
await page.setViewport({ width: 500, height: 900, deviceScaleFactor: 1 });
for (const task of config.tasks) {
await page.goto(`${baseUrl}/${task.page}`, { waitUntil: 'networkidle0' });
// 执行 action 触发弹窗/状态(action 可选)
if (task.action) {
await page.evaluate(new Function('return (' + task.action + ')()'));
await delay(300);
}
await screenshotPhoneShell(page, path.join(outDir, task.output), task.fullPage);
console.log(`Done: ${task.output}`);
}
await browser.close();
console.log(`\nAll ${config.tasks.length} screenshots saved to: ${outDir}`);
})();
@@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>驻场人员端 - 页面设计总览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #e0e0e0; }
/* 顶部导航 */
.nav { position: sticky; top: 0; z-index: 100; background: #16213e; border-bottom: 1px solid #0f3460; padding: 14px 24px; display: flex; gap: 12px; align-items: center; }
.nav__title { font-size: 16px; font-weight: 600; color: #4fc3f7; margin-right: 20px; white-space: nowrap; }
.nav__link { font-size: 13px; color: #aaa; text-decoration: none; padding: 5px 12px; border-radius: 20px; transition: all .2s; white-space: nowrap; border: 1px solid transparent; }
.nav__link:hover { background: #0f3460; color: #4fc3f7; border-color: #4fc3f7; }
/* 业务主线区块 */
.section { padding: 24px 24px 8px; }
.section__header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.section__title { font-size: 15px; font-weight: 600; color: #fff; }
.section__count { font-size: 12px; color: #666; background: #2a2a4a; padding: 2px 8px; border-radius: 10px; }
/* 横向滚动容器 */
.scroll-row { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 16px; scrollbar-width: thin; scrollbar-color: #333 transparent; }
.scroll-row::-webkit-scrollbar { height: 6px; }
.scroll-row::-webkit-scrollbar-track { background: transparent; }
.scroll-row::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
/* 卡片 */
.card { flex-shrink: 0; width: 260px; cursor: pointer; transition: transform .2s; }
.card:hover { transform: scale(1.02); }
.card__img { width: 260px; height: 564px; border-radius: 12px; overflow: hidden; border: 2px solid #2a2a4a; background: #111; transition: border-color .2s; }
.card:hover .card__img { border-color: #4fc3f7; }
.card__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.card__label { margin-top: 8px; font-size: 12px; color: #999; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card__tags { display: flex; justify-content: center; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.tag { font-size: 10px; padding: 1px 5px; border-radius: 3px; }
.tag--modal { background: #4a2800; color: #ffa940; }
.tag--state { background: #002a4a; color: #4fc3f7; }
/* 分隔线 */
.divider { height: 1px; background: #2a2a4a; margin: 8px 24px; }
/* 灯箱 */
.lightbox { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.92); align-items: center; justify-content: center; cursor: zoom-out; }
.lightbox.show { display: flex; }
.lightbox img { max-width: 90vw; max-height: 92vh; border-radius: 8px; }
.lightbox__close { position: absolute; top: 16px; right: 20px; color: #fff; font-size: 24px; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255,255,255,0.1); }
.lightbox__name { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: #ccc; font-size: 13px; background: rgba(0,0,0,0.6); padding: 6px 16px; border-radius: 20px; }
</style>
</head>
<body>
<!-- 顶部导航 -->
<nav class="nav">
<span class="nav__title">驻场人员端 · 设计总览</span>
<a class="nav__link" href="#sec-workorder">应急工单</a>
<a class="nav__link" href="#sec-serious">大病就医</a>
<a class="nav__link" href="#sec-knowledge">知识库</a>
<a class="nav__link" href="#sec-profile">个人中心</a>
</nav>
<!-- 应急工单 -->
<section class="section" id="sec-workorder">
<div class="section__header">
<h2 class="section__title">应急工单</h2>
<span class="section__count">6 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/index.jpg','工作台首页')">
<div class="card__img"><img src="screenshots/index.jpg" alt="工作台首页"></div>
<div class="card__label">工作台首页</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing.jpg','工单详情(进行中)')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing.jpg" alt="工单详情(进行中)"></div>
<div class="card__label">工单详情(进行中)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing-complete.jpg','进行中·完成处理弹窗')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing-complete.jpg" alt="进行中·完成处理弹窗"></div>
<div class="card__label">进行中·完成处理弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing-contact.jpg','进行中·联系操作人员')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing-contact.jpg" alt="进行中·联系操作人员"></div>
<div class="card__label">进行中·联系操作人员</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing-transfer.jpg','进行中·转单选择')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing-transfer.jpg" alt="进行中·转单选择"></div>
<div class="card__label">进行中·转单选择</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail.jpg','工单详情(已完成)')">
<div class="card__img"><img src="screenshots/work-order-detail.jpg" alt="工单详情(已完成)"></div>
<div class="card__label">工单详情(已完成)</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 大病就医 -->
<section class="section" id="sec-serious">
<div class="section__header">
<h2 class="section__title">大病就医</h2>
<span class="section__count">6 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/serious-illness-list.jpg','大病就医列表')">
<div class="card__img"><img src="screenshots/serious-illness-list.jpg" alt="大病就医列表"></div>
<div class="card__label">大病就医列表</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-pending.jpg','详情(待处理)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-pending.jpg" alt="详情(待处理)"></div>
<div class="card__label">详情(待处理)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-pending-submit.jpg','待处理·提交挂号结果')">
<div class="card__img"><img src="screenshots/serious-illness-detail-pending-submit.jpg" alt="待处理·提交挂号结果"></div>
<div class="card__label">待处理·提交挂号结果</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-pending-transfer.jpg','待处理·转单选择')">
<div class="card__img"><img src="screenshots/serious-illness-detail-pending-transfer.jpg" alt="待处理·转单选择"></div>
<div class="card__label">待处理·转单选择</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-done.jpg','详情(已完成)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-done.jpg" alt="详情(已完成)"></div>
<div class="card__label">详情(已完成)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-cancelled.jpg','详情(已取消)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-cancelled.jpg" alt="详情(已取消)"></div>
<div class="card__label">详情(已取消)</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 知识库 -->
<section class="section" id="sec-knowledge">
<div class="section__header">
<h2 class="section__title">知识库</h2>
<span class="section__count">2 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/knowledge-index.jpg','知识库首页')">
<div class="card__img"><img src="screenshots/knowledge-index.jpg" alt="知识库首页"></div>
<div class="card__label">知识库首页</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/knowledge-article-detail.jpg','知识详情')">
<div class="card__img"><img src="screenshots/knowledge-article-detail.jpg" alt="知识详情"></div>
<div class="card__label">知识详情</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 个人中心 -->
<section class="section" id="sec-profile">
<div class="section__header">
<h2 class="section__title">个人中心</h2>
<span class="section__count">5 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/profile-index.jpg','个人中心主页')">
<div class="card__img"><img src="screenshots/profile-index.jpg" alt="个人中心主页"></div>
<div class="card__label">个人中心主页</div>
</div>
<div class="card" onclick="openLightbox('screenshots/profile-index-logout.jpg','退出登录确认弹窗')">
<div class="card__img"><img src="screenshots/profile-index-logout.jpg" alt="退出登录确认弹窗"></div>
<div class="card__label">退出登录确认弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/edit-profile.jpg','修改个人信息')">
<div class="card__img"><img src="screenshots/edit-profile.jpg" alt="修改个人信息"></div>
<div class="card__label">修改个人信息</div>
</div>
<div class="card" onclick="openLightbox('screenshots/edit-profile-avatar.jpg','修改信息·头像选择')">
<div class="card__img"><img src="screenshots/edit-profile-avatar.jpg" alt="修改信息·头像选择"></div>
<div class="card__label">修改信息·头像选择</div>
<div class="card__tags"><span class="tag tag--modal">操作列表</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/change-pwd.jpg','修改密码')">
<div class="card__img"><img src="screenshots/change-pwd.jpg" alt="修改密码"></div>
<div class="card__label">修改密码</div>
</div>
</div>
</section>
<div style="height:40px;"></div>
<!-- 灯箱 -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<span class="lightbox__close">&times;</span>
<img id="lightbox-img" src="" alt="">
<div class="lightbox__name" id="lightbox-name"></div>
</div>
<script>
function openLightbox(src, name) {
document.getElementById('lightbox-img').src = src;
document.getElementById('lightbox-name').textContent = name;
document.getElementById('lightbox').classList.add('show');
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('show');
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeLightbox();
});
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 80 KiB

@@ -0,0 +1,257 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>操作人员端 - 页面设计总览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #e0e0e0; }
/* 顶部导航 */
.nav { position: sticky; top: 0; z-index: 100; background: #16213e; border-bottom: 1px solid #0f3460; padding: 14px 24px; display: flex; gap: 12px; align-items: center; }
.nav__title { font-size: 16px; font-weight: 600; color: #4fc3f7; margin-right: 20px; white-space: nowrap; }
.nav__link { font-size: 13px; color: #aaa; text-decoration: none; padding: 5px 12px; border-radius: 20px; transition: all .2s; white-space: nowrap; border: 1px solid transparent; }
.nav__link:hover { background: #0f3460; color: #4fc3f7; border-color: #4fc3f7; }
/* 业务主线区块 */
.section { padding: 24px 24px 8px; }
.section__header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.section__title { font-size: 15px; font-weight: 600; color: #fff; }
.section__count { font-size: 12px; color: #666; background: #2a2a4a; padding: 2px 8px; border-radius: 10px; }
/* 横向滚动容器 */
.scroll-row { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 16px; scrollbar-width: thin; scrollbar-color: #333 transparent; }
.scroll-row::-webkit-scrollbar { height: 6px; }
.scroll-row::-webkit-scrollbar-track { background: transparent; }
.scroll-row::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
/* 卡片 */
.card { flex-shrink: 0; width: 260px; cursor: pointer; transition: transform .2s; }
.card:hover { transform: scale(1.02); }
.card__img { width: 260px; height: 564px; border-radius: 12px; overflow: hidden; border: 2px solid #2a2a4a; background: #111; transition: border-color .2s; }
.card:hover .card__img { border-color: #4fc3f7; }
.card__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.card__label { margin-top: 8px; font-size: 12px; color: #999; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card__tags { display: flex; justify-content: center; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.tag { font-size: 10px; padding: 1px 5px; border-radius: 3px; }
.tag--modal { background: #4a2800; color: #ffa940; }
.tag--state { background: #002a4a; color: #4fc3f7; }
/* 分隔线 */
.divider { height: 1px; background: #2a2a4a; margin: 8px 24px; }
/* 灯箱 */
.lightbox { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.92); align-items: center; justify-content: center; cursor: zoom-out; }
.lightbox.show { display: flex; }
.lightbox img { max-width: 90vw; max-height: 92vh; border-radius: 8px; }
.lightbox__close { position: absolute; top: 16px; right: 20px; color: #fff; font-size: 24px; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255,255,255,0.1); }
.lightbox__name { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: #ccc; font-size: 13px; background: rgba(0,0,0,0.6); padding: 6px 16px; border-radius: 20px; }
</style>
</head>
<body>
<!-- 顶部导航 -->
<nav class="nav">
<span class="nav__title">操作人员端 · 设计总览</span>
<a class="nav__link" href="#sec-emergency">应急求助</a>
<a class="nav__link" href="#sec-serious">大病就医</a>
<a class="nav__link" href="#sec-knowledge">知识库</a>
<a class="nav__link" href="#sec-profile">个人中心</a>
</nav>
<!-- 应急求助 -->
<section class="section" id="sec-emergency">
<div class="section__header">
<h2 class="section__title">应急求助</h2>
<span class="section__count">11 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/index.jpg','工作台首页')">
<div class="card__img"><img src="screenshots/index.jpg" alt="工作台首页"></div>
<div class="card__label">工作台首页</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat.jpg','应急聊天(进行中)')">
<div class="card__img"><img src="screenshots/emergency-chat.jpg" alt="应急聊天(进行中)"></div>
<div class="card__label">应急聊天(进行中)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-ongoing.jpg','应急聊天·媒体面板')">
<div class="card__img"><img src="screenshots/emergency-chat-ongoing.jpg" alt="应急聊天·媒体面板"></div>
<div class="card__label">应急聊天·媒体面板</div>
<div class="card__tags"><span class="tag tag--state">面板</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/end-emergency.jpg','结束应急弹窗')">
<div class="card__img"><img src="screenshots/end-emergency.jpg" alt="结束应急弹窗"></div>
<div class="card__label">结束应急弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-done.jpg','应急聊天(已结束)')">
<div class="card__img"><img src="screenshots/emergency-chat-done.jpg" alt="应急聊天(已结束)"></div>
<div class="card__label">应急聊天(已结束)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/dispatch-onsite.jpg','驻场派单')">
<div class="card__img"><img src="screenshots/dispatch-onsite.jpg" alt="驻场派单"></div>
<div class="card__label">驻场派单</div>
</div>
<div class="card" onclick="openLightbox('screenshots/dispatch-ambulance.jpg','救护车支援')">
<div class="card__img"><img src="screenshots/dispatch-ambulance.jpg" alt="救护车支援"></div>
<div class="card__label">救护车支援</div>
</div>
<div class="card" onclick="openLightbox('screenshots/rescue-summary.jpg','救助信息汇总')">
<div class="card__img"><img src="screenshots/rescue-summary.jpg" alt="救助信息汇总"></div>
<div class="card__label">救助信息汇总</div>
</div>
<div class="card" onclick="openLightbox('screenshots/patient-location.jpg','患者定位地图')">
<div class="card__img"><img src="screenshots/patient-location.jpg" alt="患者定位地图"></div>
<div class="card__label">患者定位地图</div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing.jpg','工单详情(进行中)')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing.jpg" alt="工单详情(进行中)"></div>
<div class="card__label">工单详情(进行中)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail.jpg','工单详情(已完成)')">
<div class="card__img"><img src="screenshots/work-order-detail.jpg" alt="工单详情(已完成)"></div>
<div class="card__label">工单详情(已完成)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-dialog.jpg','工单详情·补充小结弹窗')">
<div class="card__img"><img src="screenshots/work-order-detail-dialog.jpg" alt="工单详情·补充小结弹窗"></div>
<div class="card__label">工单详情·补充小结弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 大病就医 -->
<section class="section" id="sec-serious">
<div class="section__header">
<h2 class="section__title">大病就医</h2>
<span class="section__count">8 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/serious-illness-list.jpg','大病就医列表')">
<div class="card__img"><img src="screenshots/serious-illness-list.jpg" alt="大病就医列表"></div>
<div class="card__label">大病就医列表</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-pending.jpg','详情(待确认)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-pending.jpg" alt="详情(待确认)"></div>
<div class="card__label">详情(待确认)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-pending-confirm.jpg','待确认·确认派单弹窗')">
<div class="card__img"><img src="screenshots/serious-illness-detail-pending-confirm.jpg" alt="待确认·确认派单弹窗"></div>
<div class="card__label">待确认·确认派单弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-pending-cancel.jpg','待确认·取消预约弹窗')">
<div class="card__img"><img src="screenshots/serious-illness-detail-pending-cancel.jpg" alt="待确认·取消预约弹窗"></div>
<div class="card__label">待确认·取消预约弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-confirmed.jpg','详情(已确认)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-confirmed.jpg" alt="详情(已确认)"></div>
<div class="card__label">详情(已确认)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-confirmed-cancel.jpg','已确认·取消预约弹窗')">
<div class="card__img"><img src="screenshots/serious-illness-detail-confirmed-cancel.jpg" alt="已确认·取消预约弹窗"></div>
<div class="card__label">已确认·取消预约弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-done.jpg','详情(已完成)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-done.jpg" alt="详情(已完成)"></div>
<div class="card__label">详情(已完成)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/serious-illness-detail-cancelled.jpg','详情(已取消)')">
<div class="card__img"><img src="screenshots/serious-illness-detail-cancelled.jpg" alt="详情(已取消)"></div>
<div class="card__label">详情(已取消)</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 知识库 -->
<section class="section" id="sec-knowledge">
<div class="section__header">
<h2 class="section__title">知识库</h2>
<span class="section__count">2 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/knowledge-index.jpg','知识库首页')">
<div class="card__img"><img src="screenshots/knowledge-index.jpg" alt="知识库首页"></div>
<div class="card__label">知识库首页</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/knowledge-article-detail.jpg','知识详情')">
<div class="card__img"><img src="screenshots/knowledge-article-detail.jpg" alt="知识详情"></div>
<div class="card__label">知识详情</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 个人中心 -->
<section class="section" id="sec-profile">
<div class="section__header">
<h2 class="section__title">个人中心</h2>
<span class="section__count">7 页</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/profile-index.jpg','个人中心主页')">
<div class="card__img"><img src="screenshots/profile-index.jpg" alt="个人中心主页"></div>
<div class="card__label">个人中心主页</div>
</div>
<div class="card" onclick="openLightbox('screenshots/profile-index-logout.jpg','退出登录确认弹窗')">
<div class="card__img"><img src="screenshots/profile-index-logout.jpg" alt="退出登录确认弹窗"></div>
<div class="card__label">退出登录确认弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/edit-profile.jpg','修改个人信息')">
<div class="card__img"><img src="screenshots/edit-profile.jpg" alt="修改个人信息"></div>
<div class="card__label">修改个人信息</div>
</div>
<div class="card" onclick="openLightbox('screenshots/change-pwd.jpg','修改密码')">
<div class="card__img"><img src="screenshots/change-pwd.jpg" alt="修改密码"></div>
<div class="card__label">修改密码</div>
</div>
<div class="card" onclick="openLightbox('screenshots/change-pwd-success.jpg','修改密码成功提示')">
<div class="card__img"><img src="screenshots/change-pwd-success.jpg" alt="修改密码成功提示"></div>
<div class="card__label">修改密码成功提示</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/duty-schedule.jpg','值班信息')">
<div class="card__img"><img src="screenshots/duty-schedule.jpg" alt="值班信息"></div>
<div class="card__label">值班信息</div>
</div>
<div class="card" onclick="openLightbox('screenshots/duty-config.jpg','排班配置')">
<div class="card__img"><img src="screenshots/duty-config.jpg" alt="排班配置"></div>
<div class="card__label">排班配置</div>
</div>
</div>
</section>
<div style="height:40px;"></div>
<!-- 灯箱 -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<span class="lightbox__close">&times;</span>
<img id="lightbox-img" src="" alt="">
<div class="lightbox__name" id="lightbox-name"></div>
</div>
<script>
function openLightbox(src, name) {
document.getElementById('lightbox-img').src = src;
document.getElementById('lightbox-name').textContent = name;
document.getElementById('lightbox').classList.add('show');
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('show');
}
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeLightbox();
});
</script>
Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

@@ -0,0 +1,238 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>健康应急APP专业人员端 - 页面设计总览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #e0e0e0; }
/* 顶部导航 */
.nav { position: sticky; top: 0; z-index: 100; background: #16213e; border-bottom: 1px solid #0f3460; padding: 14px 24px; display: flex; gap: 12px; align-items: center; }
.nav__title { font-size: 16px; font-weight: 600; color: #4fc3f7; margin-right: 20px; white-space: nowrap; }
.nav__link { font-size: 13px; color: #aaa; text-decoration: none; padding: 5px 12px; border-radius: 20px; transition: all .2s; white-space: nowrap; border: 1px solid transparent; }
.nav__link:hover { background: #0f3460; color: #4fc3f7; border-color: #4fc3f7; }
/* 业务主线区块 */
.section { padding: 24px 24px 8px; }
.section__header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.section__title { font-size: 15px; font-weight: 600; color: #fff; }
.section__count { font-size: 12px; color: #666; background: #2a2a4a; padding: 2px 8px; border-radius: 10px; }
/* 横向滚动容器 */
.scroll-row { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 16px; scrollbar-width: thin; scrollbar-color: #333 transparent; }
.scroll-row::-webkit-scrollbar { height: 6px; }
.scroll-row::-webkit-scrollbar-track { background: transparent; }
.scroll-row::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
/* 卡片 */
.card { flex-shrink: 0; width: 260px; cursor: pointer; transition: transform .2s; }
.card:hover { transform: scale(1.02); }
.card__img { width: 260px; height: 564px; border-radius: 12px; overflow: hidden; border: 2px solid #2a2a4a; background: #111; transition: border-color .2s; }
.card:hover .card__img { border-color: #4fc3f7; }
.card__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.card__label { margin-top: 8px; font-size: 12px; color: #999; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card__tags { display: flex; justify-content: center; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.tag { font-size: 10px; padding: 1px 5px; border-radius: 3px; }
.tag--modal { background: #4a2800; color: #ffa940; }
.tag--state { background: #002a4a; color: #4fc3f7; }
/* 分隔线 */
.divider { height: 1px; background: #2a2a4a; margin: 8px 24px; }
/* 灯箱 */
.lightbox { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.92); align-items: center; justify-content: center; cursor: zoom-out; }
.lightbox.show { display: flex; }
.lightbox img { max-width: 90vw; max-height: 92vh; border-radius: 8px; }
.lightbox__close { position: absolute; top: 16px; right: 20px; color: #fff; font-size: 24px; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255,255,255,0.1); }
.lightbox__name { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: #ccc; font-size: 13px; background: rgba(0,0,0,0.6); padding: 6px 16px; border-radius: 20px; }
</style>
</head>
<body>
<!-- 顶部导航 -->
<nav class="nav">
<span class="nav__title">健康应急APP专业人员端 · 设计总览</span>
<a class="nav__link" href="#sec-workbench">工作台</a>
<a class="nav__link" href="#sec-knowledge">知识库</a>
<a class="nav__link" href="#sec-profile">我的</a>
</nav>
<!-- 工作台 -->
<section class="section" id="sec-workbench">
<div class="section__header">
<h2 class="section__title">工作台</h2>
<span class="section__count">17 页面形态</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/index.jpg','工单列表-进行中')">
<div class="card__img"><img src="screenshots/index.jpg" alt=""></div>
<div class="card__label">工单列表-进行中</div>
</div>
<div class="card" onclick="openLightbox('screenshots/index-done.jpg','工单列表-已结束')">
<div class="card__img"><img src="screenshots/index-done.jpg" alt=""></div>
<div class="card__label">工单列表-已结束</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-ongoing.jpg','应急聊天-进行中')">
<div class="card__img"><img src="screenshots/emergency-chat-ongoing.jpg" alt=""></div>
<div class="card__label">应急聊天-进行中</div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-ongoing-info.jpg','应急聊天-患者信息展开')">
<div class="card__img"><img src="screenshots/emergency-chat-ongoing-info.jpg" alt=""></div>
<div class="card__label">应急聊天-患者信息展开</div>
<div class="card__tags"><span class="tag tag--state">展开状态</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-ongoing-voice.jpg','应急聊天-语音模式')">
<div class="card__img"><img src="screenshots/emergency-chat-ongoing-voice.jpg" alt=""></div>
<div class="card__label">应急聊天-语音模式</div>
<div class="card__tags"><span class="tag tag--state">模式切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-ongoing-media.jpg','应急聊天-媒体面板')">
<div class="card__img"><img src="screenshots/emergency-chat-ongoing-media.jpg" alt=""></div>
<div class="card__label">应急聊天-媒体面板</div>
<div class="card__tags"><span class="tag tag--modal">面板</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-ongoing-confirm.jpg','应急聊天-结束确认')">
<div class="card__img"><img src="screenshots/emergency-chat-ongoing-confirm.jpg" alt=""></div>
<div class="card__label">应急聊天-结束确认</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-done.jpg','应急聊天-已结束')">
<div class="card__img"><img src="screenshots/emergency-chat-done.jpg" alt=""></div>
<div class="card__label">应急聊天-已结束</div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-done-info.jpg','应急聊天已结束-信息展开')">
<div class="card__img"><img src="screenshots/emergency-chat-done-info.jpg" alt=""></div>
<div class="card__label">应急聊天已结束-信息展开</div>
<div class="card__tags"><span class="tag tag--state">展开状态</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail.jpg','工单详情-已完成')">
<div class="card__img"><img src="screenshots/work-order-detail.jpg" alt=""></div>
<div class="card__label">工单详情-已完成</div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-edit.jpg','工单详情-编辑意见弹窗')">
<div class="card__img"><img src="screenshots/work-order-detail-edit.jpg" alt=""></div>
<div class="card__label">工单详情-编辑意见弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing.jpg','工单详情-进行中')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing.jpg" alt=""></div>
<div class="card__label">工单详情-进行中</div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing-edit.jpg','工单详情进行中-编辑弹窗')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing-edit.jpg" alt=""></div>
<div class="card__label">工单详情进行中-编辑弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/work-order-detail-ongoing-confirm.jpg','工单详情进行中-结束确认')">
<div class="card__img"><img src="screenshots/work-order-detail-ongoing-confirm.jpg" alt=""></div>
<div class="card__label">工单详情进行中-结束确认</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/patient-location.jpg','患者定位')">
<div class="card__img"><img src="screenshots/patient-location.jpg" alt=""></div>
<div class="card__label">患者定位</div>
</div>
<div class="card" onclick="openLightbox('screenshots/patient-location-card.jpg','患者定位-资源卡片')">
<div class="card__img"><img src="screenshots/patient-location-card.jpg" alt=""></div>
<div class="card__label">患者定位-资源卡片</div>
<div class="card__tags"><span class="tag tag--state">卡片展开</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/rescue-opinion.jpg','救助意见')">
<div class="card__img"><img src="screenshots/rescue-opinion.jpg" alt=""></div>
<div class="card__label">救助意见</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 知识库 -->
<section class="section" id="sec-knowledge">
<div class="section__header">
<h2 class="section__title">知识库</h2>
<span class="section__count">3 页面形态</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/knowledge-index.jpg','知识库-文章列表')">
<div class="card__img"><img src="screenshots/knowledge-index.jpg" alt=""></div>
<div class="card__label">知识库-文章列表</div>
</div>
<div class="card" onclick="openLightbox('screenshots/knowledge-index-rule.jpg','知识库-规章制度')">
<div class="card__img"><img src="screenshots/knowledge-index-rule.jpg" alt=""></div>
<div class="card__label">知识库-规章制度</div>
<div class="card__tags"><span class="tag tag--state">Tab切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/knowledge-article-detail.jpg','知识详情')">
<div class="card__img"><img src="screenshots/knowledge-article-detail.jpg" alt=""></div>
<div class="card__label">知识详情</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- 我的 -->
<section class="section" id="sec-profile">
<div class="section__header">
<h2 class="section__title">我的</h2>
<span class="section__count">7 页面形态</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/profile-index.jpg','个人中心')">
<div class="card__img"><img src="screenshots/profile-index.jpg" alt=""></div>
<div class="card__label">个人中心</div>
</div>
<div class="card" onclick="openLightbox('screenshots/profile-index-logout.jpg','个人中心-退出确认')">
<div class="card__img"><img src="screenshots/profile-index-logout.jpg" alt=""></div>
<div class="card__label">个人中心-退出确认</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/edit-profile.jpg','修改个人信息')">
<div class="card__img"><img src="screenshots/edit-profile.jpg" alt=""></div>
<div class="card__label">修改个人信息</div>
</div>
<div class="card" onclick="openLightbox('screenshots/profile-edit-sheet.jpg','修改信息-头像选择')">
<div class="card__img"><img src="screenshots/profile-edit-sheet.jpg" alt=""></div>
<div class="card__label">修改信息-头像选择</div>
<div class="card__tags"><span class="tag tag--modal">ActionSheet</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/change-pwd.jpg','修改密码')">
<div class="card__img"><img src="screenshots/change-pwd.jpg" alt=""></div>
<div class="card__label">修改密码</div>
</div>
<div class="card" onclick="openLightbox('screenshots/profile-change-pwd-modal.jpg','修改密码-成功确认')">
<div class="card__img"><img src="screenshots/profile-change-pwd-modal.jpg" alt=""></div>
<div class="card__label">修改密码-成功确认</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/duty-schedule.jpg','值班信息')">
<div class="card__img"><img src="screenshots/duty-schedule.jpg" alt=""></div>
<div class="card__label">值班信息</div>
</div>
</div>
</section>
<div style="height:40px;"></div>
<!-- 灯箱 -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<span class="lightbox__close">&times;</span>
<img id="lightbox-img" src="" alt="">
<div class="lightbox__name" id="lightbox-name"></div>
</div>
<script>
function openLightbox(src, name) {
document.getElementById('lightbox-img').src = src;
document.getElementById('lightbox-name').textContent = name;
document.getElementById('lightbox').classList.add('show');
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('show');
}
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

@@ -0,0 +1,288 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>应急就医 - 页面设计总览</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #1a1a2e; color: #e0e0e0; }
/* 顶部导航 */
.nav { position: sticky; top: 0; z-index: 100; background: #16213e; border-bottom: 1px solid #0f3460; padding: 14px 24px; display: flex; gap: 12px; align-items: center; }
.nav__title { font-size: 16px; font-weight: 600; color: #4fc3f7; margin-right: 20px; white-space: nowrap; }
.nav__link { font-size: 13px; color: #aaa; text-decoration: none; padding: 5px 12px; border-radius: 20px; transition: all .2s; white-space: nowrap; border: 1px solid transparent; }
.nav__link:hover { background: #0f3460; color: #4fc3f7; border-color: #4fc3f7; }
/* 业务主线区块 */
.section { padding: 24px 24px 8px; }
.section__header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.section__title { font-size: 15px; font-weight: 600; color: #fff; }
.section__count { font-size: 12px; color: #666; background: #2a2a4a; padding: 2px 8px; border-radius: 10px; }
/* 横向滚动容器 */
.scroll-row { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 16px; scrollbar-width: thin; scrollbar-color: #333 transparent; }
.scroll-row::-webkit-scrollbar { height: 6px; }
.scroll-row::-webkit-scrollbar-track { background: transparent; }
.scroll-row::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
/* 卡片 */
.card { flex-shrink: 0; width: 260px; cursor: pointer; transition: transform .2s; }
.card:hover { transform: scale(1.02); }
.card__img { width: 260px; height: 564px; border-radius: 12px; overflow: hidden; border: 2px solid #2a2a4a; background: #111; transition: border-color .2s; }
.card:hover .card__img { border-color: #4fc3f7; }
.card__img img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.card__label { margin-top: 8px; font-size: 12px; color: #999; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.card__tags { display: flex; justify-content: center; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.tag { font-size: 10px; padding: 1px 5px; border-radius: 3px; }
.tag--modal { background: #4a2800; color: #ffa940; }
.tag--state { background: #002a4a; color: #4fc3f7; }
/* 子标题 */
.sub-title { font-size: 12px; color: #666; margin: 12px 0 8px 4px; padding-left: 24px; }
/* 分隔线 */
.divider { height: 1px; background: #2a2a4a; margin: 8px 24px; }
/* 灯箱 */
.lightbox { display: none; position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,0.92); align-items: center; justify-content: center; cursor: zoom-out; }
.lightbox.show { display: flex; }
.lightbox img { max-width: 90vw; max-height: 92vh; border-radius: 8px; }
.lightbox__close { position: absolute; top: 16px; right: 20px; color: #fff; font-size: 24px; cursor: pointer; width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; border-radius: 50%; background: rgba(255,255,255,0.1); }
.lightbox__name { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); color: #ccc; font-size: 13px; background: rgba(0,0,0,0.6); padding: 6px 16px; border-radius: 20px; }
</style>
</head>
<body>
<!-- 顶部导航 -->
<nav class="nav">
<span class="nav__title">应急就医员工端APP · 设计总览</span>
<a class="nav__link" href="#sec-entry">入口</a>
<a class="nav__link" href="#sec-map">资源地图</a>
<a class="nav__link" href="#sec-detail">资源详情</a>
<a class="nav__link" href="#sec-help">应急求助</a>
<a class="nav__link" href="#sec-video">急救教学</a>
<a class="nav__link" href="#sec-appt">大病就医预约</a>
</nav>
<!-- ===== 1. 入口与总览 ===== -->
<section class="section" id="sec-entry">
<div class="section__header">
<h2 class="section__title">入口与总览</h2>
<span class="section__count">2</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/index.jpg','应急就医首页')">
<div class="card__img"><img src="screenshots/index.jpg" alt=""></div>
<div class="card__label">应急就医首页</div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-contacts.jpg','紧急联系人')">
<div class="card__img"><img src="screenshots/emergency-contacts.jpg" alt=""></div>
<div class="card__label">紧急联系人</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ===== 2. 应急资源地图 ===== -->
<section class="section" id="sec-map">
<div class="section__header">
<h2 class="section__title">应急资源地图</h2>
<span class="section__count">6</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/resource-map.jpg','油田医院地图')">
<div class="card__img"><img src="screenshots/resource-map.jpg" alt=""></div>
<div class="card__label">油田医院地图(默认)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/resource-map-clinic.jpg','医疗点地图')">
<div class="card__img"><img src="screenshots/resource-map-clinic.jpg" alt=""></div>
<div class="card__label">医疗点地图</div>
</div>
<div class="card" onclick="openLightbox('screenshots/resource-map-aed.jpg','AED地图')">
<div class="card__img"><img src="screenshots/resource-map-aed.jpg" alt=""></div>
<div class="card__label">AED 地图</div>
</div>
<div class="card" onclick="openLightbox('screenshots/resource-map-ambulance.jpg','救护车地图')">
<div class="card__img"><img src="screenshots/resource-map-ambulance.jpg" alt=""></div>
<div class="card__label">救护车地图</div>
</div>
<div class="card" onclick="openLightbox('screenshots/resource-map-kit.jpg','急救包地图')">
<div class="card__img"><img src="screenshots/resource-map-kit.jpg" alt=""></div>
<div class="card__label">急救包地图</div>
</div>
<div class="card" onclick="openLightbox('screenshots/resource-map-simulate.jpg','模拟急救面板')">
<div class="card__img"><img src="screenshots/resource-map-simulate.jpg" alt=""></div>
<div class="card__label">模拟急救面板</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ===== 3. 资源详情 ===== -->
<section class="section" id="sec-detail">
<div class="section__header">
<h2 class="section__title">资源详情页</h2>
<span class="section__count">6</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/hospital-detail.jpg','油田医院详情')">
<div class="card__img"><img src="screenshots/hospital-detail.jpg" alt=""></div>
<div class="card__label">油田医院详情</div>
<div class="card__tags"><span class="tag tag--state">展开/收起</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/clinic-detail.jpg','医疗点详情')">
<div class="card__img"><img src="screenshots/clinic-detail.jpg" alt=""></div>
<div class="card__label">医疗点详情</div>
</div>
<div class="card" onclick="openLightbox('screenshots/aed-detail.jpg','AED详情')">
<div class="card__img"><img src="screenshots/aed-detail.jpg" alt=""></div>
<div class="card__label">AED 详情</div>
</div>
<div class="card" onclick="openLightbox('screenshots/ambulance-detail.jpg','救护车详情')">
<div class="card__img"><img src="screenshots/ambulance-detail.jpg" alt=""></div>
<div class="card__label">救护车详情</div>
</div>
<div class="card" onclick="openLightbox('screenshots/first-aid-kit-detail.jpg','急救包详情')">
<div class="card__img"><img src="screenshots/first-aid-kit-detail.jpg" alt=""></div>
<div class="card__label">急救包详情</div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-tips.jpg','急救提示书')">
<div class="card__img"><img src="screenshots/emergency-tips.jpg" alt=""></div>
<div class="card__label">急救提示书</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ===== 4. 应急求助 ===== -->
<section class="section" id="sec-help">
<div class="section__header">
<h2 class="section__title">应急求助</h2>
<span class="section__count">5</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/emergency-chat.jpg','应急视频对话')">
<div class="card__img"><img src="screenshots/emergency-chat.jpg" alt=""></div>
<div class="card__label">应急视频对话(文字模式)</div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-voice.jpg','语音输入模式')">
<div class="card__img"><img src="screenshots/emergency-chat-voice.jpg" alt=""></div>
<div class="card__label">语音输入模式</div>
<div class="card__tags"><span class="tag tag--state">状态切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-plus.jpg','加号菜单展开')">
<div class="card__img"><img src="screenshots/emergency-chat-plus.jpg" alt=""></div>
<div class="card__label">加号菜单展开</div>
<div class="card__tags"><span class="tag tag--state">状态切换</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/emergency-chat-modal.jpg','结束应急确认弹窗')">
<div class="card__img"><img src="screenshots/emergency-chat-modal.jpg" alt=""></div>
<div class="card__label">结束应急确认弹窗</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/help-records.jpg','应急求助记录')">
<div class="card__img"><img src="screenshots/help-records.jpg" alt=""></div>
<div class="card__label">应急求助记录</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ===== 5. 急救教学 ===== -->
<section class="section" id="sec-video">
<div class="section__header">
<h2 class="section__title">急救教学</h2>
<span class="section__count">1</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/first-aid-videos.jpg','急救教学视频')">
<div class="card__img"><img src="screenshots/first-aid-videos.jpg" alt=""></div>
<div class="card__label">急救教学视频列表</div>
</div>
</div>
</section>
<div class="divider"></div>
<!-- ===== 6. 大病就医预约 ===== -->
<section class="section" id="sec-appt">
<div class="section__header">
<h2 class="section__title">大病就医预约</h2>
<span class="section__count">11</span>
</div>
<div class="scroll-row">
<div class="card" onclick="openLightbox('screenshots/appointment-list.jpg','预约列表·待确认')">
<div class="card__img"><img src="screenshots/appointment-list.jpg" alt=""></div>
<div class="card__label">列表 · 待确认</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-list-confirmed.jpg','预约列表·已确认')">
<div class="card__img"><img src="screenshots/appointment-list-confirmed.jpg" alt=""></div>
<div class="card__label">列表 · 已确认</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-list-done.jpg','预约列表·已完成')">
<div class="card__img"><img src="screenshots/appointment-list-done.jpg" alt=""></div>
<div class="card__label">列表 · 已完成</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-list-cancelled.jpg','预约列表·已取消')">
<div class="card__img"><img src="screenshots/appointment-list-cancelled.jpg" alt=""></div>
<div class="card__label">列表 · 已取消</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-form.jpg','发起预约表单')">
<div class="card__img"><img src="screenshots/appointment-form.jpg" alt=""></div>
<div class="card__label">发起预约表单</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-detail-pending.jpg','预约详情·待确认')">
<div class="card__img"><img src="screenshots/appointment-detail-pending.jpg" alt=""></div>
<div class="card__label">详情 · 待确认</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-detail-pending-modal.jpg','取消预约弹窗(待确认)')">
<div class="card__img"><img src="screenshots/appointment-detail-pending-modal.jpg" alt=""></div>
<div class="card__label">取消弹窗(待确认)</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-detail-confirmed.jpg','预约详情·已确认')">
<div class="card__img"><img src="screenshots/appointment-detail-confirmed.jpg" alt=""></div>
<div class="card__label">详情 · 已确认</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-detail-confirmed-modal.jpg','取消预约弹窗(已确认)')">
<div class="card__img"><img src="screenshots/appointment-detail-confirmed-modal.jpg" alt=""></div>
<div class="card__label">取消弹窗(已确认)</div>
<div class="card__tags"><span class="tag tag--modal">弹窗</span></div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-detail-done.jpg','预约详情·已完成')">
<div class="card__img"><img src="screenshots/appointment-detail-done.jpg" alt=""></div>
<div class="card__label">详情 · 已完成</div>
</div>
<div class="card" onclick="openLightbox('screenshots/appointment-detail-cancelled.jpg','预约详情·已取消')">
<div class="card__img"><img src="screenshots/appointment-detail-cancelled.jpg" alt=""></div>
<div class="card__label">详情 · 已取消</div>
</div>
</div>
</section>
<div style="height:40px;"></div>
<!-- 灯箱 -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
<span class="lightbox__close">&times;</span>
<img id="lightbox-img" src="" alt="">
<div class="lightbox__name" id="lightbox-name"></div>
</div>
<script>
function openLightbox(src, name) {
document.getElementById('lightbox-img').src = src;
document.getElementById('lightbox-name').textContent = name;
document.getElementById('lightbox').classList.add('show');
}
function closeLightbox() {
document.getElementById('lightbox').classList.remove('show');
}
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

+5 -1
View File
@@ -563,6 +563,7 @@ const SITE_MAP = [
{ file:'consult-flowchart.html', label:'咨询流程图' }
]},
{ name:'应急就医', dir:'employee-app/emergency-medical', entry:'index.html', prd:'employee-app/emergency-medical/doc/PRD.md', done:true, pages:[
{ file:'doc/design-overview.html', label:'页面总览' },
{ file:'index.html', label:'应急就医主页' },
{ file:'emergency-chat.html', label:'应急对话' },
{ file:'resource-map.html', label:'应急资源地图' },
@@ -649,6 +650,7 @@ const SITE_MAP = [
]},
{ role:'应急操作人员', id:'operator', modules:[
{name:'工作台',dir:'emergency-app/operator/workbench',prd:'emergency-app/operator/doc/PRD.md',done:true,pages:[
{file:'../doc/design-overview.html',label:'页面总览'},
{file:'index.html',label:'工作台首页(应急求助)'},
{file:'serious-illness-list.html',label:'大病就医首页'},
{file:'emergency-chat.html',label:'应急聊天'},
@@ -677,6 +679,7 @@ const SITE_MAP = [
]},
{ role:'应急专业人员', id:'professional', modules:[
{ name:'工作台', dir:'emergency-app/professional/workbench', prd:'emergency-app/professional/doc/PRD.md', done:true, pages:[
{file:'../doc/design-overview.html',label:'页面总览'},
{file:'index.html',label:'工作台首页'},
{file:'emergency-chat-ongoing.html',label:'应急聊天(进行中)'},
{file:'emergency-chat-done.html',label:'应急聊天(已结束)'},
@@ -696,6 +699,7 @@ const SITE_MAP = [
]},
{ role:'应急驻场人员', id:'onsite', modules:[
{name:'工作台',dir:'emergency-app/onsite/workbench',prd:'emergency-app/onsite/doc/PRD.md',done:true,pages:[
{file:'../doc/design-overview.html',label:'页面总览'},
{file:'index.html',label:'工作台首页(应急求助)'},
{file:'serious-illness-list.html',label:'大病就医首页'},
{file:'work-order-detail-ongoing.html',label:'工单详情(待处理)'},
@@ -972,7 +976,7 @@ tabNav.addEventListener('click', e => {
/* ===== Markdown 预览(新标签页打开) ===== */
function openMdPreview(filePath, title) {
window.open('md-viewer.html?file=' + encodeURIComponent(filePath) + '&title=' + encodeURIComponent(title || ''), '_blank');
window.open('_templates/md-viewer.html?file=' + encodeURIComponent(filePath) + '&title=' + encodeURIComponent(title || ''), '_blank');
}
</script>
</body>
-16
View File
@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools.js" "$@"
else
exec node "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools.js" "$@"
fi
-16
View File
@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js" "$@"
else
exec node "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js" "$@"
fi
-17
View File
@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\chrome-devtools-mcp\build\src\bin\chrome-devtools-mcp.js" %*
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js" $args
} else {
& "$basedir/node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js" $args
} else {
& "node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools-mcp.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
-17
View File
@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\chrome-devtools-mcp\build\src\bin\chrome-devtools.js" %*
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools.js" $args
} else {
& "$basedir/node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools.js" $args
} else {
& "node$exe" "$basedir/../chrome-devtools-mcp/build/src/bin/chrome-devtools.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
-16
View File
@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../playwright/cli.js" "$@"
else
exec node "$basedir/../playwright/cli.js" "$@"
fi
-16
View File
@@ -1,16 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../playwright-core/cli.js" "$@"
else
exec node "$basedir/../playwright-core/cli.js" "$@"
fi
-17
View File
@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright-core\cli.js" %*
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../playwright-core/cli.js" $args
} else {
& "node$exe" "$basedir/../playwright-core/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
-17
View File
@@ -1,17 +0,0 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright\cli.js" %*
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../playwright/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../playwright/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../playwright/cli.js" $args
} else {
& "node$exe" "$basedir/../playwright/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+238 -64
View File
@@ -1,12 +1,38 @@
{
"name": "platform-prototype",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@babel/code-frame": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz",
"integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.29.7",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
"integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@puppeteer/browsers": {
"version": "2.13.1",
"resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.1.tgz",
"integrity": "sha512-zmS4RTK9fbrc++WlAJhxYbfz3IjDeOmkK/CwwbLmk7ydfS9e2CiEeRJHEPvjDVElO/bwXbidwGA37Bsm6LzCnQ==",
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz",
"integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -33,14 +59,14 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "25.6.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.2.tgz",
"integrity": "sha512-sokuT28dxf9JT5Kady1fsXOvI4HVpjZa95NKT5y9PNTIrs2AsobR4GFAA90ZG8M+nxVRLysCXsVj6eGC7Vbrlw==",
"version": "25.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.1.tgz",
"integrity": "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"undici-types": "~7.19.0"
"undici-types": ">=7.24.0 <7.24.7"
}
},
"node_modules/@types/yauzl": {
@@ -90,6 +116,13 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"dev": true,
"license": "Python-2.0"
},
"node_modules/ast-types": {
"version": "0.13.4",
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
@@ -119,9 +152,9 @@
}
},
"node_modules/bare-events": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.2.tgz",
"integrity": "sha512-riJjyv1/mHLIPX4RwiK+oW9/4c3TEUeORHKefKAKnZ5kyslbN+HXowtbaVEqt4IMUB7OXlfixcs6gsFeo/jhiQ==",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz",
"integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==",
"dev": true,
"license": "Apache-2.0",
"peerDependencies": {
@@ -235,17 +268,14 @@
"node": "*"
}
},
"node_modules/chrome-devtools-mcp": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/chrome-devtools-mcp/-/chrome-devtools-mcp-0.21.0.tgz",
"integrity": "sha512-d+iqrRmcwpRFV3Q4DRCF2LCoq+WCRU3GhISKQ9v8g+1C2Uh8upj3urkjxNO4QIjhBMIYei/VQ1OQLFceby80Og==",
"license": "Apache-2.0",
"bin": {
"chrome-devtools": "build/src/bin/chrome-devtools.js",
"chrome-devtools-mcp": "build/src/bin/chrome-devtools-mcp.js"
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^20.19.0 || ^22.12.0 || >=23"
"node": ">=6"
}
},
"node_modules/chromium-bidi": {
@@ -297,6 +327,33 @@
"dev": true,
"license": "MIT"
},
"node_modules/cosmiconfig": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz",
"integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"env-paths": "^2.2.1",
"import-fresh": "^3.3.0",
"js-yaml": "^4.1.0",
"parse-json": "^5.2.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/d-fischer"
},
"peerDependencies": {
"typescript": ">=4.9.5"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/data-uri-to-buffer": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
@@ -364,6 +421,26 @@
"once": "^1.4.0"
}
},
"node_modules/env-paths": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/error-ex": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz",
"integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.2.1"
}
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
@@ -547,6 +624,23 @@
"node": ">= 14"
}
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
"integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"parent-module": "^1.0.0",
"resolve-from": "^4.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/ip-address": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
@@ -557,6 +651,13 @@
"node": ">= 12"
}
},
"node_modules/is-arrayish": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
"integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
"dev": true,
"license": "MIT"
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
@@ -567,6 +668,40 @@
"node": ">=8"
}
},
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"dev": true,
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
"integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
"dev": true,
"license": "MIT"
},
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true,
"license": "MIT"
},
"node_modules/lru-cache": {
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
@@ -645,6 +780,38 @@
"node": ">= 14"
}
},
"node_modules/parent-module": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
"dev": true,
"license": "MIT",
"dependencies": {
"callsites": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/parse-json": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.0.0",
"error-ex": "^1.3.1",
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pend": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -652,37 +819,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/playwright": {
"version": "1.59.1",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.1.tgz",
"integrity": "sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==",
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.59.1"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.59.1",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.1.tgz",
"integrity": "sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
"license": "ISC"
},
"node_modules/progress": {
"version": "2.0.3",
@@ -732,14 +874,36 @@
"once": "^1.3.1"
}
},
"node_modules/puppeteer-core": {
"version": "24.43.0",
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.0.tgz",
"integrity": "sha512-cCRNXsUlhyPoKDz6+TiSpfZpRS3mD6Y1YFKhkdr6ik6TMfuJb7fAtXq9ThUFc4sphxObDk3BuAvdxc1Y6YOnqQ==",
"node_modules/puppeteer": {
"version": "24.43.1",
"resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.43.1.tgz",
"integrity": "sha512-/FSOViCrqRdb1HDocpsM9Z1giA71gTQPUt3SpHGVRALKAy/rJr1fLFYZW9F23qPxqVxTHQnbh/5B5opJST3kAw==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"@puppeteer/browsers": "2.13.2",
"chromium-bidi": "14.0.0",
"cosmiconfig": "^9.0.0",
"devtools-protocol": "0.0.1608973",
"puppeteer-core": "24.43.1",
"typed-query-selector": "^2.12.2"
},
"bin": {
"puppeteer": "lib/cjs/puppeteer/node/cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/puppeteer/node_modules/puppeteer-core": {
"version": "24.43.1",
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.1.tgz",
"integrity": "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@puppeteer/browsers": "2.13.1",
"@puppeteer/browsers": "2.13.2",
"chromium-bidi": "14.0.0",
"debug": "^4.4.3",
"devtools-protocol": "0.0.1608973",
@@ -761,10 +925,20 @@
"node": ">=0.10.0"
}
},
"node_modules/resolve-from": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/semver": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
"version": "7.8.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz",
"integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==",
"dev": true,
"license": "ISC",
"bin": {
@@ -929,9 +1103,9 @@
"license": "MIT"
},
"node_modules/undici-types": {
"version": "7.19.2",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"dev": true,
"license": "MIT",
"optional": true
@@ -969,9 +1143,9 @@
"license": "ISC"
},
"node_modules/ws": {
"version": "8.20.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz",
"integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==",
"version": "8.21.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
"dev": true,
"license": "MIT",
"engines": {
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+19
View File
@@ -0,0 +1,19 @@
# @babel/code-frame
> Generate errors that contain a code frame that point to source locations.
See our website [@babel/code-frame](https://babeljs.io/docs/babel-code-frame) for more information.
## Install
Using npm:
```sh
npm install --save-dev @babel/code-frame
```
or using yarn:
```sh
yarn add @babel/code-frame --dev
```
+217
View File
@@ -0,0 +1,217 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var picocolors = require('picocolors');
var jsTokens = require('js-tokens');
var helperValidatorIdentifier = require('@babel/helper-validator-identifier');
function isColorSupported() {
return (typeof process === "object" && (process.env.FORCE_COLOR === "0" || process.env.FORCE_COLOR === "false") ? false : picocolors.isColorSupported
);
}
const compose = (f, g) => v => f(g(v));
function buildDefs(colors) {
return {
keyword: colors.cyan,
capitalized: colors.yellow,
jsxIdentifier: colors.yellow,
punctuator: colors.yellow,
number: colors.magenta,
string: colors.green,
regex: colors.magenta,
comment: colors.gray,
invalid: compose(compose(colors.white, colors.bgRed), colors.bold),
gutter: colors.gray,
marker: compose(colors.red, colors.bold),
message: compose(colors.red, colors.bold),
reset: colors.reset
};
}
const defsOn = buildDefs(picocolors.createColors(true));
const defsOff = buildDefs(picocolors.createColors(false));
function getDefs(enabled) {
return enabled ? defsOn : defsOff;
}
const sometimesKeywords = new Set(["as", "async", "from", "get", "of", "set"]);
const NEWLINE$1 = /\r\n|[\n\r\u2028\u2029]/;
const BRACKET = /^[()[\]{}]$/;
let tokenize;
const JSX_TAG = /^[a-z][\w-]*$/i;
const getTokenType = function (token, offset, text) {
if (token.type === "name") {
const tokenValue = token.value;
if (helperValidatorIdentifier.isKeyword(tokenValue) || helperValidatorIdentifier.isStrictReservedWord(tokenValue, true) || sometimesKeywords.has(tokenValue)) {
return "keyword";
}
if (JSX_TAG.test(tokenValue) && (text[offset - 1] === "<" || text.slice(offset - 2, offset) === "</")) {
return "jsxIdentifier";
}
const firstChar = String.fromCodePoint(tokenValue.codePointAt(0));
if (firstChar !== firstChar.toLowerCase()) {
return "capitalized";
}
}
if (token.type === "punctuator" && BRACKET.test(token.value)) {
return "bracket";
}
if (token.type === "invalid" && (token.value === "@" || token.value === "#")) {
return "punctuator";
}
return token.type;
};
tokenize = function* (text) {
let match;
while (match = jsTokens.default.exec(text)) {
const token = jsTokens.matchToToken(match);
yield {
type: getTokenType(token, match.index, text),
value: token.value
};
}
};
function highlight(text) {
if (text === "") return "";
const defs = getDefs(true);
let highlighted = "";
for (const {
type,
value
} of tokenize(text)) {
if (type in defs) {
highlighted += value.split(NEWLINE$1).map(str => defs[type](str)).join("\n");
} else {
highlighted += value;
}
}
return highlighted;
}
let deprecationWarningShown = false;
const NEWLINE = /\r\n|[\n\r\u2028\u2029]/;
function getMarkerLines(loc, source, opts, startLineBaseZero) {
const startLoc = Object.assign({
column: 0,
line: -1
}, loc.start);
const endLoc = Object.assign({}, startLoc, loc.end);
const {
linesAbove = 2,
linesBelow = 3
} = opts || {};
const startLine = startLoc.line - startLineBaseZero;
const startColumn = startLoc.column;
const endLine = endLoc.line - startLineBaseZero;
const endColumn = endLoc.column;
let start = Math.max(startLine - (linesAbove + 1), 0);
let end = Math.min(source.length, endLine + linesBelow);
if (startLine === -1) {
start = 0;
}
if (endLine === -1) {
end = source.length;
}
const lineDiff = endLine - startLine;
const markerLines = {};
if (lineDiff) {
for (let i = 0; i <= lineDiff; i++) {
const lineNumber = i + startLine;
if (!startColumn) {
markerLines[lineNumber] = true;
} else if (i === 0) {
const sourceLength = source[lineNumber - 1].length;
markerLines[lineNumber] = [startColumn, sourceLength - startColumn + 1];
} else if (i === lineDiff) {
markerLines[lineNumber] = [0, endColumn];
} else {
const sourceLength = source[lineNumber - i].length;
markerLines[lineNumber] = [0, sourceLength];
}
}
} else {
if (startColumn === endColumn) {
if (startColumn) {
markerLines[startLine] = [startColumn, 0];
} else {
markerLines[startLine] = true;
}
} else {
markerLines[startLine] = [startColumn, endColumn - startColumn];
}
}
return {
start,
end,
markerLines
};
}
function codeFrameColumns(rawLines, loc, opts = {}) {
const shouldHighlight = opts.forceColor || isColorSupported() && opts.highlightCode;
const startLineBaseZero = (opts.startLine || 1) - 1;
const defs = getDefs(shouldHighlight);
const lines = rawLines.split(NEWLINE);
const {
start,
end,
markerLines
} = getMarkerLines(loc, lines, opts, startLineBaseZero);
const hasColumns = loc.start && typeof loc.start.column === "number";
const numberMaxWidth = String(end + startLineBaseZero).length;
const highlightedLines = shouldHighlight ? highlight(rawLines) : rawLines;
let frame = highlightedLines.split(NEWLINE, end).slice(start, end).map((line, index) => {
const number = start + 1 + index;
const paddedNumber = ` ${number + startLineBaseZero}`.slice(-numberMaxWidth);
const gutter = ` ${paddedNumber} |`;
const hasMarker = markerLines[number];
const lastMarkerLine = !markerLines[number + 1];
if (hasMarker) {
let markerLine = "";
if (Array.isArray(hasMarker)) {
const markerSpacing = line.slice(0, Math.max(hasMarker[0] - 1, 0)).replace(/[^\t]/g, " ");
const numberOfMarkers = hasMarker[1] || 1;
markerLine = ["\n ", defs.gutter(gutter.replace(/\d/g, " ")), " ", markerSpacing, defs.marker("^").repeat(numberOfMarkers)].join("");
if (lastMarkerLine && opts.message) {
markerLine += " " + defs.message(opts.message);
}
}
return [defs.marker(">"), defs.gutter(gutter), line.length > 0 ? ` ${line}` : "", markerLine].join("");
} else {
return ` ${defs.gutter(gutter)}${line.length > 0 ? ` ${line}` : ""}`;
}
}).join("\n");
if (opts.message && !hasColumns) {
frame = `${" ".repeat(numberMaxWidth + 1)}${opts.message}\n${frame}`;
}
if (shouldHighlight) {
return defs.reset(frame);
} else {
return frame;
}
}
function index (rawLines, lineNumber, colNumber, opts = {}) {
if (!deprecationWarningShown) {
deprecationWarningShown = true;
const message = "Passing lineNumber and colNumber is deprecated to @babel/code-frame. Please use `codeFrameColumns`.";
if (process.emitWarning) {
process.emitWarning(message, "DeprecationWarning");
} else {
const deprecationError = new Error(message);
deprecationError.name = "DeprecationWarning";
console.warn(new Error(message));
}
}
colNumber = Math.max(colNumber, 0);
const location = {
start: {
column: colNumber,
line: lineNumber
}
};
return codeFrameColumns(rawLines, location, opts);
}
exports.codeFrameColumns = codeFrameColumns;
exports.default = index;
exports.highlight = highlight;
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
+32
View File
@@ -0,0 +1,32 @@
{
"name": "@babel/code-frame",
"version": "7.29.7",
"description": "Generate errors that contain a code frame that point to source locations.",
"author": "The Babel Team (https://babel.dev/team)",
"homepage": "https://babel.dev/docs/en/next/babel-code-frame",
"bugs": "https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-code-frame"
},
"main": "./lib/index.js",
"dependencies": {
"@babel/helper-validator-identifier": "^7.29.7",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"devDependencies": {
"charcodes": "^0.2.0",
"import-meta-resolve": "^4.1.0",
"strip-ansi": "^4.0.0"
},
"engines": {
"node": ">=6.9.0"
},
"type": "commonjs"
}
+22
View File
@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+19
View File
@@ -0,0 +1,19 @@
# @babel/helper-validator-identifier
> Validate identifier/keywords name
See our website [@babel/helper-validator-identifier](https://babeljs.io/docs/babel-helper-validator-identifier) for more information.
## Install
Using npm:
```sh
npm install --save @babel/helper-validator-identifier
```
or using yarn:
```sh
yarn add @babel/helper-validator-identifier
```
+70
View File
@@ -0,0 +1,70 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isIdentifierChar = isIdentifierChar;
exports.isIdentifierName = isIdentifierName;
exports.isIdentifierStart = isIdentifierStart;
let nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u052f\u0531-\u0556\u0559\u0560-\u0588\u05d0-\u05ea\u05ef-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u0860-\u086a\u0870-\u0887\u0889-\u088f\u08a0-\u08c9\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u09fc\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0af9\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c58-\u0c5a\u0c5c\u0c5d\u0c60\u0c61\u0c80\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cdc-\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d04-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d54-\u0d56\u0d5f-\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e86-\u0e8a\u0e8c-\u0ea3\u0ea5\u0ea7-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f8\u1700-\u1711\u171f-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1878\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4c\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1c80-\u1c8a\u1c90-\u1cba\u1cbd-\u1cbf\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1cfa\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2118-\u211d\u2124\u2126\u2128\u212a-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309b-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312f\u3131-\u318e\u31a0-\u31bf\u31f0-\u31ff\u3400-\u4dbf\u4e00-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua69d\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua7dc\ua7f1-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua8fd\ua8fe\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\ua9e0-\ua9e4\ua9e6-\ua9ef\ua9fa-\ua9fe\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa7e-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab5a\uab5c-\uab69\uab70-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
let nonASCIIidentifierChars = "\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u07fd\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u0897-\u089f\u08ca-\u08e1\u08e3-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u09fe\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0afa-\u0aff\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b55-\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c04\u0c3c\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0cf3\u0d00-\u0d03\u0d3b\u0d3c\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d81-\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0ebc\u0ec8-\u0ece\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1715\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u180f-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1abf-\u1add\u1ae0-\u1aeb\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf4\u1cf7-\u1cf9\u1dc0-\u1dff\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\u30fb\ua620-\ua629\ua66f\ua674-\ua67d\ua69e\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua82c\ua880\ua881\ua8b4-\ua8c5\ua8d0-\ua8d9\ua8e0-\ua8f1\ua8ff-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2f\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f\uff65";
const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null;
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 13, 10, 2, 14, 2, 6, 2, 1, 2, 10, 2, 14, 2, 6, 2, 1, 4, 51, 13, 310, 10, 21, 11, 7, 25, 5, 2, 41, 2, 8, 70, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 7, 25, 39, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 28, 43, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 14, 35, 39, 27, 10, 22, 251, 41, 7, 1, 17, 5, 57, 28, 11, 0, 9, 21, 43, 17, 47, 20, 28, 22, 13, 52, 58, 1, 3, 0, 14, 44, 33, 24, 27, 35, 30, 0, 3, 0, 9, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 20, 1, 64, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 31, 9, 2, 0, 3, 0, 2, 37, 2, 0, 26, 0, 2, 0, 45, 52, 19, 3, 21, 2, 31, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 14, 0, 72, 26, 38, 6, 186, 43, 117, 63, 32, 7, 3, 0, 3, 7, 2, 1, 2, 23, 16, 0, 2, 0, 95, 7, 3, 38, 17, 0, 2, 0, 29, 0, 11, 39, 8, 0, 22, 0, 12, 45, 20, 0, 19, 72, 200, 32, 32, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 26, 5, 2, 1, 2, 31, 15, 0, 24, 43, 261, 18, 16, 0, 2, 12, 2, 33, 125, 0, 80, 921, 103, 110, 18, 195, 2637, 96, 16, 1071, 18, 5, 26, 3994, 6, 582, 6842, 29, 1763, 568, 8, 30, 18, 78, 18, 29, 19, 47, 17, 3, 32, 20, 6, 18, 433, 44, 212, 63, 33, 24, 3, 24, 45, 74, 6, 0, 67, 12, 65, 1, 2, 0, 15, 4, 10, 7381, 42, 31, 98, 114, 8702, 3, 2, 6, 2, 1, 2, 290, 16, 0, 30, 2, 3, 0, 15, 3, 9, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 1845, 30, 7, 5, 262, 61, 147, 44, 11, 6, 17, 0, 322, 29, 19, 43, 485, 27, 229, 29, 3, 0, 208, 30, 2, 2, 2, 1, 2, 6, 3, 4, 10, 1, 225, 6, 2, 3, 2, 1, 2, 14, 2, 196, 60, 67, 8, 0, 1205, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42719, 33, 4381, 3, 5773, 3, 7472, 16, 621, 2467, 541, 1507, 4938, 6, 8489];
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 574, 3, 9, 9, 7, 9, 32, 4, 318, 1, 78, 5, 71, 10, 50, 3, 123, 2, 54, 14, 32, 10, 3, 1, 11, 3, 46, 10, 8, 0, 46, 9, 7, 2, 37, 13, 2, 9, 6, 1, 45, 0, 13, 2, 49, 13, 9, 3, 2, 11, 83, 11, 7, 0, 3, 0, 158, 11, 6, 9, 7, 3, 56, 1, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 68, 8, 2, 0, 3, 0, 2, 3, 2, 4, 2, 0, 15, 1, 83, 17, 10, 9, 5, 0, 82, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 7, 19, 58, 14, 5, 9, 243, 14, 166, 9, 71, 5, 2, 1, 3, 3, 2, 0, 2, 1, 13, 9, 120, 6, 3, 6, 4, 0, 29, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 199, 7, 137, 9, 54, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 49, 4, 2, 1, 2, 4, 9, 9, 55, 9, 266, 3, 10, 1, 2, 0, 49, 6, 4, 4, 14, 10, 5350, 0, 7, 14, 11465, 27, 2343, 9, 87, 9, 39, 4, 60, 6, 26, 9, 535, 9, 470, 0, 2, 54, 8, 3, 82, 0, 12, 1, 19628, 1, 4178, 9, 519, 45, 3, 22, 543, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 101, 0, 161, 6, 10, 9, 357, 0, 62, 13, 499, 13, 245, 1, 2, 9, 233, 0, 3, 0, 8, 1, 6, 0, 475, 6, 110, 6, 6, 9, 4759, 9, 787719, 239];
function isInAstralSet(code, set) {
let pos = 0x10000;
for (let i = 0, length = set.length; i < length; i += 2) {
pos += set[i];
if (pos > code) return false;
pos += set[i + 1];
if (pos >= code) return true;
}
return false;
}
function isIdentifierStart(code) {
if (code < 65) return code === 36;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes);
}
function isIdentifierChar(code) {
if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
if (code <= 90) return true;
if (code < 97) return code === 95;
if (code <= 122) return true;
if (code <= 0xffff) {
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes);
}
function isIdentifierName(name) {
let isFirst = true;
for (let i = 0; i < name.length; i++) {
let cp = name.charCodeAt(i);
if ((cp & 0xfc00) === 0xd800 && i + 1 < name.length) {
const trail = name.charCodeAt(++i);
if ((trail & 0xfc00) === 0xdc00) {
cp = 0x10000 + ((cp & 0x3ff) << 10) + (trail & 0x3ff);
}
}
if (isFirst) {
isFirst = false;
if (!isIdentifierStart(cp)) {
return false;
}
} else if (!isIdentifierChar(cp)) {
return false;
}
}
return !isFirst;
}
//# sourceMappingURL=identifier.js.map
File diff suppressed because one or more lines are too long
+57
View File
@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "isIdentifierChar", {
enumerable: true,
get: function () {
return _identifier.isIdentifierChar;
}
});
Object.defineProperty(exports, "isIdentifierName", {
enumerable: true,
get: function () {
return _identifier.isIdentifierName;
}
});
Object.defineProperty(exports, "isIdentifierStart", {
enumerable: true,
get: function () {
return _identifier.isIdentifierStart;
}
});
Object.defineProperty(exports, "isKeyword", {
enumerable: true,
get: function () {
return _keyword.isKeyword;
}
});
Object.defineProperty(exports, "isReservedWord", {
enumerable: true,
get: function () {
return _keyword.isReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindOnlyReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindOnlyReservedWord;
}
});
Object.defineProperty(exports, "isStrictBindReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictBindReservedWord;
}
});
Object.defineProperty(exports, "isStrictReservedWord", {
enumerable: true,
get: function () {
return _keyword.isStrictReservedWord;
}
});
var _identifier = require("./identifier.js");
var _keyword = require("./keyword.js");
//# sourceMappingURL=index.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["_identifier","require","_keyword"],"sources":["../src/index.ts"],"sourcesContent":["export {\n isIdentifierName,\n isIdentifierChar,\n isIdentifierStart,\n} from \"./identifier.ts\";\nexport {\n isReservedWord,\n isStrictBindOnlyReservedWord,\n isStrictBindReservedWord,\n isStrictReservedWord,\n isKeyword,\n} from \"./keyword.ts\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,WAAA,GAAAC,OAAA;AAKA,IAAAC,QAAA,GAAAD,OAAA","ignoreList":[]}
+35
View File
@@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.isKeyword = isKeyword;
exports.isReservedWord = isReservedWord;
exports.isStrictBindOnlyReservedWord = isStrictBindOnlyReservedWord;
exports.isStrictBindReservedWord = isStrictBindReservedWord;
exports.isStrictReservedWord = isStrictReservedWord;
const reservedWords = {
keyword: ["break", "case", "catch", "continue", "debugger", "default", "do", "else", "finally", "for", "function", "if", "return", "switch", "throw", "try", "var", "const", "while", "with", "new", "this", "super", "class", "extends", "export", "import", "null", "true", "false", "in", "instanceof", "typeof", "void", "delete"],
strict: ["implements", "interface", "let", "package", "private", "protected", "public", "static", "yield"],
strictBind: ["eval", "arguments"]
};
const keywords = new Set(reservedWords.keyword);
const reservedWordsStrictSet = new Set(reservedWords.strict);
const reservedWordsStrictBindSet = new Set(reservedWords.strictBind);
function isReservedWord(word, inModule) {
return inModule && word === "await" || word === "enum";
}
function isStrictReservedWord(word, inModule) {
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
}
function isStrictBindOnlyReservedWord(word) {
return reservedWordsStrictBindSet.has(word);
}
function isStrictBindReservedWord(word, inModule) {
return isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word);
}
function isKeyword(word) {
return keywords.has(word);
}
//# sourceMappingURL=keyword.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"names":["reservedWords","keyword","strict","strictBind","keywords","Set","reservedWordsStrictSet","reservedWordsStrictBindSet","isReservedWord","word","inModule","isStrictReservedWord","has","isStrictBindOnlyReservedWord","isStrictBindReservedWord","isKeyword"],"sources":["../src/keyword.ts"],"sourcesContent":["const reservedWords = {\n keyword: [\n \"break\",\n \"case\",\n \"catch\",\n \"continue\",\n \"debugger\",\n \"default\",\n \"do\",\n \"else\",\n \"finally\",\n \"for\",\n \"function\",\n \"if\",\n \"return\",\n \"switch\",\n \"throw\",\n \"try\",\n \"var\",\n \"const\",\n \"while\",\n \"with\",\n \"new\",\n \"this\",\n \"super\",\n \"class\",\n \"extends\",\n \"export\",\n \"import\",\n \"null\",\n \"true\",\n \"false\",\n \"in\",\n \"instanceof\",\n \"typeof\",\n \"void\",\n \"delete\",\n ],\n strict: [\n \"implements\",\n \"interface\",\n \"let\",\n \"package\",\n \"private\",\n \"protected\",\n \"public\",\n \"static\",\n \"yield\",\n ],\n strictBind: [\"eval\", \"arguments\"],\n};\nconst keywords = new Set(reservedWords.keyword);\nconst reservedWordsStrictSet = new Set(reservedWords.strict);\nconst reservedWordsStrictBindSet = new Set(reservedWords.strictBind);\n\n/**\n * Checks if word is a reserved word in non-strict mode\n */\nexport function isReservedWord(word: string, inModule: boolean): boolean {\n return (inModule && word === \"await\") || word === \"enum\";\n}\n\n/**\n * Checks if word is a reserved word in non-binding strict mode\n *\n * Includes non-strict reserved words\n */\nexport function isStrictReservedWord(word: string, inModule: boolean): boolean {\n return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode, but it is allowed as\n * a normal identifier.\n */\nexport function isStrictBindOnlyReservedWord(word: string): boolean {\n return reservedWordsStrictBindSet.has(word);\n}\n\n/**\n * Checks if word is a reserved word in binding strict mode\n *\n * Includes non-strict reserved words and non-binding strict reserved words\n */\nexport function isStrictBindReservedWord(\n word: string,\n inModule: boolean,\n): boolean {\n return (\n isStrictReservedWord(word, inModule) || isStrictBindOnlyReservedWord(word)\n );\n}\n\nexport function isKeyword(word: string): boolean {\n return keywords.has(word);\n}\n"],"mappings":";;;;;;;;;;AAAA,MAAMA,aAAa,GAAG;EACpBC,OAAO,EAAE,CACP,OAAO,EACP,MAAM,EACN,OAAO,EACP,UAAU,EACV,UAAU,EACV,SAAS,EACT,IAAI,EACJ,MAAM,EACN,SAAS,EACT,KAAK,EACL,UAAU,EACV,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,EACN,KAAK,EACL,MAAM,EACN,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,MAAM,EACN,OAAO,EACP,IAAI,EACJ,YAAY,EACZ,QAAQ,EACR,MAAM,EACN,QAAQ,CACT;EACDC,MAAM,EAAE,CACN,YAAY,EACZ,WAAW,EACX,KAAK,EACL,SAAS,EACT,SAAS,EACT,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,CACR;EACDC,UAAU,EAAE,CAAC,MAAM,EAAE,WAAW;AAClC,CAAC;AACD,MAAMC,QAAQ,GAAG,IAAIC,GAAG,CAACL,aAAa,CAACC,OAAO,CAAC;AAC/C,MAAMK,sBAAsB,GAAG,IAAID,GAAG,CAACL,aAAa,CAACE,MAAM,CAAC;AAC5D,MAAMK,0BAA0B,GAAG,IAAIF,GAAG,CAACL,aAAa,CAACG,UAAU,CAAC;AAK7D,SAASK,cAAcA,CAACC,IAAY,EAAEC,QAAiB,EAAW;EACvE,OAAQA,QAAQ,IAAID,IAAI,KAAK,OAAO,IAAKA,IAAI,KAAK,MAAM;AAC1D;AAOO,SAASE,oBAAoBA,CAACF,IAAY,EAAEC,QAAiB,EAAW;EAC7E,OAAOF,cAAc,CAACC,IAAI,EAAEC,QAAQ,CAAC,IAAIJ,sBAAsB,CAACM,GAAG,CAACH,IAAI,CAAC;AAC3E;AAMO,SAASI,4BAA4BA,CAACJ,IAAY,EAAW;EAClE,OAAOF,0BAA0B,CAACK,GAAG,CAACH,IAAI,CAAC;AAC7C;AAOO,SAASK,wBAAwBA,CACtCL,IAAY,EACZC,QAAiB,EACR;EACT,OACEC,oBAAoB,CAACF,IAAI,EAAEC,QAAQ,CAAC,IAAIG,4BAA4B,CAACJ,IAAI,CAAC;AAE9E;AAEO,SAASM,SAASA,CAACN,IAAY,EAAW;EAC/C,OAAOL,QAAQ,CAACQ,GAAG,CAACH,IAAI,CAAC;AAC3B","ignoreList":[]}
+31
View File
@@ -0,0 +1,31 @@
{
"name": "@babel/helper-validator-identifier",
"version": "7.29.7",
"description": "Validate identifier/keywords name",
"repository": {
"type": "git",
"url": "https://github.com/babel/babel.git",
"directory": "packages/babel-helper-validator-identifier"
},
"license": "MIT",
"publishConfig": {
"access": "public"
},
"main": "./lib/index.js",
"exports": {
".": {
"types": "./lib/index.d.ts",
"default": "./lib/index.js"
},
"./package.json": "./package.json"
},
"devDependencies": {
"@unicode/unicode-17.0.0": "^1.6.10",
"charcodes": "^0.2.0"
},
"engines": {
"node": ">=6.9.0"
},
"author": "The Babel Team (https://babel.dev/team)",
"type": "commonjs"
}
+1 -1
View File
@@ -54,7 +54,7 @@ function isValidPlatform(platform) {
}
// If moved update release-please config
// x-release-please-start-version
const packageVersion = '2.13.1';
const packageVersion = '2.13.2';
// x-release-please-end
/**
* @public
+1 -1
View File
@@ -266,7 +266,7 @@ async function runSetup(installedBrowser) {
return;
}
(0, node_child_process_1.spawnSync)(node_path_1.default.join(browserDir, 'setup.exe'), [`--configure-browser-in-directory=` + browserDir], {
shell: true,
shell: false,
});
// TODO: Handle error here. Currently the setup.exe sometimes
// errors although it sets the permissions correctly.
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -18,7 +18,7 @@ function isValidPlatform(platform) {
}
// If moved update release-please config
// x-release-please-start-version
const packageVersion = '2.13.1';
const packageVersion = '2.13.2';
// x-release-please-end
/**
* @public
+1 -1
View File
@@ -255,7 +255,7 @@ async function runSetup(installedBrowser) {
return;
}
spawnSync(path.join(browserDir, 'setup.exe'), [`--configure-browser-in-directory=` + browserDir], {
shell: true,
shell: false,
});
// TODO: Handle error here. Currently the setup.exe sometimes
// errors although it sets the permissions correctly.
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@puppeteer/browsers",
"version": "2.13.1",
"version": "2.13.2",
"description": "Download and launch browsers",
"scripts": {
"build:docs": "wireit",
+1 -1
View File
@@ -47,7 +47,7 @@ function isValidPlatform(platform: unknown): platform is BrowserPlatform {
// If moved update release-please config
// x-release-please-start-version
const packageVersion = '2.13.1';
const packageVersion = '2.13.2';
// x-release-please-end
/**
+1 -1
View File
@@ -492,7 +492,7 @@ async function runSetup(installedBrowser: InstalledBrowser): Promise<void> {
path.join(browserDir, 'setup.exe'),
[`--configure-browser-in-directory=` + browserDir],
{
shell: true,
shell: false,
},
);
// TODO: Handle error here. Currently the setup.exe sometimes
+1 -1
View File
@@ -8,7 +8,7 @@ This package contains type definitions for node (https://nodejs.org/).
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node.
### Additional Details
* Last updated: Thu, 07 May 2026 22:21:35 GMT
* Last updated: Tue, 19 May 2026 17:48:56 GMT
* Dependencies: [undici-types](https://npmjs.com/package/undici-types)
# Credits
+108
View File
@@ -491,6 +491,75 @@ declare module "node:async_hooks" {
* @experimental
*/
exit<R, TArgs extends any[]>(callback: (...args: TArgs) => R, ...args: TArgs): R;
/**
* Creates a disposable scope that enters the given store and automatically
* restores the previous store value when the scope is disposed. This method is
* designed to work with JavaScript's explicit resource management (`using` syntax).
*
* Example:
*
* ```js
* import { AsyncLocalStorage } from 'node:async_hooks';
*
* const asyncLocalStorage = new AsyncLocalStorage();
*
* {
* using _ = asyncLocalStorage.withScope('my-store');
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
* }
*
* console.log(asyncLocalStorage.getStore()); // Prints: undefined
* ```
*
* The `withScope()` method is particularly useful for managing context in
* synchronous code where you want to ensure the previous store value is restored
* when exiting a block, even if an error is thrown.
*
* ```js
* import { AsyncLocalStorage } from 'node:async_hooks';
*
* const asyncLocalStorage = new AsyncLocalStorage();
*
* try {
* using _ = asyncLocalStorage.withScope('my-store');
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
* throw new Error('test');
* } catch (e) {
* // Store is automatically restored even after error
* console.log(asyncLocalStorage.getStore()); // Prints: undefined
* }
* ```
*
* **Important:** When using `withScope()` in async functions before the first
* `await`, be aware that the scope change will affect the caller's context. The
* synchronous portion of an async function (before the first `await`) runs
* immediately when called, and when it reaches the first `await`, it returns the
* promise to the caller. At that point, the scope change becomes visible in the
* caller's context and will persist in subsequent synchronous code until something
* else changes the scope value. For async operations, prefer using `run()` which
* properly isolates context across async boundaries.
*
* ```js
* import { AsyncLocalStorage } from 'node:async_hooks';
*
* const asyncLocalStorage = new AsyncLocalStorage();
*
* async function example() {
* using _ = asyncLocalStorage.withScope('my-store');
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
* await someAsyncOperation(); // Function pauses here and returns promise
* console.log(asyncLocalStorage.getStore()); // Prints: my-store
* }
*
* // Calling without await
* example(); // Synchronous portion runs, then pauses at first await
* // After the promise is returned, the scope 'my-store' is now active in caller!
* console.log(asyncLocalStorage.getStore()); // Prints: my-store (unexpected!)
* ```
* @since v25.9.0
* @experimental
*/
withScope(store: T): RunScope;
/**
* Transitions into the context for the remainder of the current
* synchronous execution and then persists the store through any following
@@ -533,6 +602,45 @@ declare module "node:async_hooks" {
*/
enterWith(store: T): void;
}
/**
* A disposable scope returned by `asyncLocalStorage.withScope()` that
* automatically restores the previous store value when disposed. This class
* implements the [Explicit Resource Management](https://github.com/tc39/proposal-explicit-resource-management) protocol and is designed to work
* with JavaScript's `using` syntax.
*
* The scope automatically restores the previous store value when the `using` block
* exits, whether through normal completion or by throwing an error.
* @since v25.9.0
* @experimental
*/
interface RunScope extends Disposable {
/**
* Explicitly ends the scope and restores the previous store value. This method
* is idempotent: calling it multiple times has the same effect as calling it once.
*
* The `[Symbol.dispose]()` method defers to `dispose()`.
*
* If `withScope()` is called without the `using` keyword, `dispose()` must be
* called manually to restore the previous store value. Forgetting to call
* `dispose()` will cause the store value to persist for the remainder of the
* current execution context:
*
* ```js
* import { AsyncLocalStorage } from 'node:async_hooks';
*
* const storage = new AsyncLocalStorage();
*
* // Without using, the scope must be disposed manually
* const scope = storage.withScope('my-store');
* // storage.getStore() === 'my-store' here
*
* scope.dispose(); // Restore previous value
* // storage.getStore() === undefined here
* ```
* @since v25.9.0
*/
dispose(): void;
}
/**
* @since v17.2.0, v16.14.0
* @return A map of provider types to the corresponding numeric id.
+14 -3
View File
@@ -3778,7 +3778,7 @@ declare module "node:crypto" {
interface CShakeParams extends Algorithm {
customization?: NodeJS.BufferSource;
functionName?: NodeJS.BufferSource;
length: number;
outputLength: number;
}
interface ContextParams extends Algorithm {
context?: NodeJS.BufferSource;
@@ -3815,6 +3815,10 @@ declare module "node:crypto" {
hash: HashAlgorithmIdentifier;
length?: number;
}
interface KangarooTwelveParams {
customization?: NodeJS.BufferSource;
outputLength: number;
}
interface JsonWebKey {
alg?: string;
crv?: string;
@@ -3849,7 +3853,7 @@ declare module "node:crypto" {
}
interface KmacParams extends Algorithm {
customization?: NodeJS.BufferSource;
length: number;
outputLength: number;
}
interface Pbkdf2Params extends Algorithm {
hash: HashAlgorithmIdentifier;
@@ -3884,6 +3888,10 @@ declare module "node:crypto" {
interface RsaPssParams extends Algorithm {
saltLength: number;
}
interface TurboShakeParams {
domainSeparation?: number;
outputLength: number;
}
interface Crypto {
readonly subtle: SubtleCrypto;
getRandomValues<
@@ -3945,7 +3953,10 @@ declare module "node:crypto" {
extractable: boolean,
keyUsages: readonly KeyUsage[],
): Promise<CryptoKey>;
digest(algorithm: AlgorithmIdentifier | CShakeParams, data: NodeJS.BufferSource): Promise<ArrayBuffer>;
digest(
algorithm: AlgorithmIdentifier | CShakeParams | TurboShakeParams | KangarooTwelveParams,
data: NodeJS.BufferSource,
): Promise<ArrayBuffer>;
encapsulateBits(
encapsulationAlgorithm: AlgorithmIdentifier,
encapsulationKey: CryptoKey,
+6 -9
View File
@@ -528,15 +528,12 @@ declare module "node:events" {
* import { addAbortListener } from 'node:events';
*
* function example(signal) {
* let disposable;
* try {
* signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
* disposable = addAbortListener(signal, (e) => {
* // Do something when signal is aborted.
* });
* } finally {
* disposable?.[Symbol.dispose]();
* }
* signal.addEventListener('abort', (e) => e.stopImmediatePropagation());
* // addAbortListener() returns a disposable, so the `using` keyword ensures
* // the abort listener is automatically removed when this scope exits.
* using _ = addAbortListener(signal, (e) => {
* // Do something when signal is aborted.
* });
* }
* ```
* @since v20.5.0
+130 -8
View File
@@ -380,7 +380,8 @@ declare module "node:fs" {
"ready": [];
}
/**
* Instances of `fs.ReadStream` are created and returned using the {@link createReadStream} function.
* Instances of `fs.ReadStream` cannot be constructed directly. They are created and
* returned using the `fs.createReadStream()` function.
* @since v0.1.93
*/
class ReadStream extends stream.Readable {
@@ -643,7 +644,8 @@ declare module "node:fs" {
"ready": [];
}
/**
* Instances of `fs.WriteStream` are created and returned using the {@link createWriteStream} function.
* Instances of `fs.WriteStream` cannot be constructed directly. They are created and
* returned using the `fs.createWriteStream()` function.
* @since v0.1.93
*/
class WriteStream extends stream.Writable {
@@ -1144,6 +1146,7 @@ declare module "node:fs" {
options:
| (StatOptions & {
bigint?: false | undefined;
throwIfNoEntry?: true | undefined;
})
| undefined,
callback: (err: NodeJS.ErrnoException | null, stats: Stats) => void,
@@ -1152,33 +1155,82 @@ declare module "node:fs" {
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry?: true | undefined;
},
callback: (err: NodeJS.ErrnoException | null, stats: BigIntStats) => void,
): void;
function stat(
path: PathLike,
options: StatOptions | undefined,
options: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry: false;
},
callback: (err: NodeJS.ErrnoException | null, stats: Stats | undefined) => void,
): void;
function stat(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry: false;
},
callback: (err: NodeJS.ErrnoException | null, stats: BigIntStats | undefined) => void,
): void;
function stat(
path: PathLike,
options: StatOptions & {
throwIfNoEntry?: true | undefined;
},
callback: (err: NodeJS.ErrnoException | null, stats: Stats | BigIntStats) => void,
): void;
function stat(
path: PathLike,
options: StatOptions | undefined,
callback: (err: NodeJS.ErrnoException | null, stats: Stats | BigIntStats | undefined) => void,
): void;
namespace stat {
// TODO: aliased promisify signatures
/**
* Asynchronous stat(2) - Get file status.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
*/
function __promisify__(path: PathLike): Promise<Stats>;
function __promisify__(
path: PathLike,
options?: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry?: true | undefined;
},
): Promise<Stats>;
function __promisify__(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry?: true | undefined;
},
): Promise<BigIntStats>;
function __promisify__(path: PathLike, options?: StatOptions): Promise<Stats | BigIntStats>;
function __promisify__(
path: PathLike,
options: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry: false;
},
): Promise<Stats | undefined>;
function __promisify__(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry: false;
},
): Promise<BigIntStats | undefined>;
function __promisify__(
path: PathLike,
options: StatOptions & {
throwIfNoEntry?: true | undefined;
},
): Promise<Stats | BigIntStats>;
function __promisify__(path: PathLike, options?: StatOptions): Promise<Stats | BigIntStats | undefined>;
}
/** @deprecated This orphaned interface will be removed in a future version. */
interface StatSyncFn extends Function {
(path: PathLike, options?: undefined): Stats;
(
@@ -1220,7 +1272,42 @@ declare module "node:fs" {
* Synchronous stat(2) - Get file status.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
*/
const statSync: StatSyncFn;
function statSync(path: PathLike): Stats;
function statSync(
path: PathLike,
options?: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry?: true | undefined;
},
): Stats;
function statSync(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry?: true | undefined;
},
): BigIntStats;
function statSync(
path: PathLike,
options: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry: false;
},
): Stats | undefined;
function statSync(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry: false;
},
): BigIntStats | undefined;
function statSync(
path: PathLike,
options: StatOptions & {
throwIfNoEntry?: true | undefined;
},
): Stats | BigIntStats;
function statSync(path: PathLike, options?: StatOptions): Stats | BigIntStats | undefined;
/**
* Invokes the callback with the `fs.Stats` for the file descriptor.
*
@@ -1410,7 +1497,42 @@ declare module "node:fs" {
* Synchronous lstat(2) - Get file status. Does not dereference symbolic links.
* @param path A path to a file. If a URL is provided, it must use the `file:` protocol.
*/
const lstatSync: StatSyncFn;
function lstatSync(path: PathLike): Stats;
function lstatSync(
path: PathLike,
options?: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry?: true | undefined;
},
): Stats;
function lstatSync(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry?: true | undefined;
},
): BigIntStats;
function lstatSync(
path: PathLike,
options: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry: false;
},
): Stats | undefined;
function lstatSync(
path: PathLike,
options: StatOptions & {
bigint: true;
throwIfNoEntry: false;
},
): BigIntStats | undefined;
function lstatSync(
path: PathLike,
options: StatOptions & {
throwIfNoEntry?: true | undefined;
},
): Stats | BigIntStats;
function lstatSync(path: PathLike, options?: StatOptions): Stats | BigIntStats | undefined;
/**
* Creates a new link from the `existingPath` to the `newPath`. See the POSIX [`link(2)`](http://man7.org/linux/man-pages/man2/link.2.html) documentation for more detail. No arguments other than
* a possible
@@ -4461,10 +4583,10 @@ declare module "node:fs" {
}
interface StatOptions {
bigint?: boolean | undefined;
}
interface StatSyncOptions extends StatOptions {
throwIfNoEntry?: boolean | undefined;
}
/** @deprecated This orphaned interface will be removed in a future version. Use `StatOptions` instead. */
interface StatSyncOptions extends StatOptions {}
interface CopyOptionsBase {
/**
* Dereference symlinks
+150 -1
View File
@@ -37,6 +37,7 @@ declare module "node:fs/promises" {
WriteVResult,
} from "node:fs";
import { Stream } from "node:stream";
import { ByteReadableStream, Transform, Writer } from "node:stream/iter";
import { ReadableStream } from "node:stream/web";
interface FileChangeInfo<T extends string | Buffer> {
eventType: WatchEventType;
@@ -85,6 +86,57 @@ declare module "node:fs/promises" {
interface ReadableWebStreamOptions {
autoClose?: boolean | undefined;
}
interface PullOptions extends Abortable {
/**
* Close the file handle when the stream ends.
* @default false
*/
autoClose?: boolean | undefined;
/**
* Byte offset to begin reading from. When specified,
* reads use explicit positioning (`pread` semantics).
*/
start?: number | undefined;
/**
* Maximum number of bytes to read before ending the
* iterator. Reads stop when `limit` bytes have been delivered or EOF is
* reached, whichever comes first.
*/
limit?: number | undefined;
/**
* Size in bytes of the buffer allocated for each
* read operation.
* @default 131072
*/
chunkSize?: number | undefined;
}
interface WriterOptions {
/**
* Close the file handle when the writer ends or fails.
* @default false
*/
autoClose?: boolean | undefined;
/**
* Byte offset to start writing at. When specified,
* writes use explicit positioning.
*/
start?: number | undefined;
/**
* Maximum number of bytes the writer will accept.
* Async writes (`write()`, `writev()`) that would exceed the limit reject
* with `ERR_OUT_OF_RANGE`. Sync writes (`writeSync()`, `writevSync()`)
* return `false`.
*/
limit?: number | undefined;
/**
* Maximum chunk size in bytes for synchronous write
* operations. Writes larger than this threshold fall back to async I/O.
* Set this to match the reader's `chunkSize` for optimal `pipeTo()`
* performance.
* @default 131072
*/
chunkSize?: number | undefined;
}
// TODO: Add `EventEmitter` close
interface FileHandle {
/**
@@ -202,6 +254,41 @@ declare module "node:fs/promises" {
* @return Fulfills with `undefined` upon success.
*/
datasync(): Promise<void>;
/**
* Return the file contents as an async iterable using the
* [`node:stream/iter`](https://nodejs.org/docs/latest-v25.x/api/stream_iter.html) pull model. Reads are performed in `chunkSize`-byte
* chunks (default 128 KB). If transforms are provided, they are applied
* via [`stream/iter pull()`](https://nodejs.org/docs/latest-v25.x/api/stream_iter.html#pullsource-transforms-options).
*
* The file handle is locked while the iterable is being consumed and unlocked
* when iteration completes, an error occurs, or the consumer breaks.
*
* This function is only available when the `--experimental-stream-iter` flag is
* enabled.
*
* ```js
* import { open } from 'node:fs/promises';
* import { text } from 'node:stream/iter';
* import { compressGzip } from 'node:zlib/iter';
*
* const fh = await open('input.txt', 'r');
*
* // Read as text
* console.log(await text(fh.pull({ autoClose: true })));
*
* // Read 1 KB starting at byte 100
* const fh2 = await open('input.txt', 'r');
* console.log(await text(fh2.pull({ start: 100, limit: 1024, autoClose: true })));
*
* // Read with compression
* const fh3 = await open('input.txt', 'r');
* const compressed = fh3.pull(compressGzip(), { autoClose: true });
* ```
* @since v25.9.0
* @experimental
*/
pull(...transforms: Transform[]): ByteReadableStream;
pull(...args: [...transforms: Transform[], options: PullOptions]): ByteReadableStream;
/**
* Request that all data for the open file descriptor is flushed to the storage
* device. The specific implementation is operating system and device specific.
@@ -450,6 +537,45 @@ declare module "node:fs/promises" {
buffers: TBuffers,
position?: number,
): Promise<WriteVResult<TBuffers>>;
/**
* Return a [`node:stream/iter`](https://nodejs.org/docs/latest-v25.x/api/stream_iter.html) writer backed by this file handle.
*
* The writer supports both `Symbol.asyncDispose` and `Symbol.dispose`:
*
* * `await using w = fh.writer()` — if the writer is still open (no `end()`
* called), `asyncDispose` calls `fail()`. If `end()` is pending, it waits
* for it to complete.
* * `using w = fh.writer()` — calls `fail()` unconditionally.
*
* The `writeSync()` and `writevSync()` methods enable the try-sync fast path
* used by [`stream/iter pipeTo()`](https://nodejs.org/docs/latest-v25.x/api/stream_iter.html#pipetosource-transforms-writer). When the reader's chunk size matches the
* writer's `chunkSize`, all writes in a `pipeTo()` pipeline complete
* synchronously with zero promise overhead.
*
* This function is only available when the `--experimental-stream-iter` flag is
* enabled.
*
* ```js
* import { open } from 'node:fs/promises';
* import { from, pipeTo } from 'node:stream/iter';
* import { compressGzip } from 'node:zlib/iter';
*
* // Async pipeline
* const fh = await open('output.gz', 'w');
* await pipeTo(from('Hello!'), compressGzip(), fh.writer({ autoClose: true }));
*
* // Sync pipeline with limit
* const src = await open('input.txt', 'r');
* const dst = await open('output.txt', 'w');
* const w = dst.writer({ limit: 1024 * 1024 }); // Max 1 MB
* await pipeTo(src.pull({ autoClose: true }), w);
* await w.end();
* await dst.close();
* ```
* @since v25.9.0
* @experimental
*/
writer(options?: WriterOptions): Writer;
/**
* Read from a file and write to an array of [ArrayBufferView](https://developer.mozilla.org/en-US/docs/Web/API/ArrayBufferView) s
* @since v13.13.0, v12.17.0
@@ -802,19 +928,42 @@ declare module "node:fs/promises" {
* @since v10.0.0
* @return Fulfills with the {fs.Stats} object for the given `path`.
*/
function stat(path: PathLike): Promise<Stats>;
function stat(
path: PathLike,
opts?: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry?: true | undefined;
},
): Promise<Stats>;
function stat(
path: PathLike,
opts: StatOptions & {
bigint: true;
throwIfNoEntry?: true | undefined;
},
): Promise<BigIntStats>;
function stat(path: PathLike, opts?: StatOptions): Promise<Stats | BigIntStats>;
function stat(
path: PathLike,
opts: StatOptions & {
bigint?: false | undefined;
throwIfNoEntry: false;
},
): Promise<Stats | undefined>;
function stat(
path: PathLike,
opts: StatOptions & {
bigint: true;
throwIfNoEntry: false;
},
): Promise<BigIntStats | undefined>;
function stat(
path: PathLike,
opts: StatOptions & {
throwIfNoEntry?: true | undefined;
},
): Promise<Stats | BigIntStats>;
function stat(path: PathLike, opts?: StatOptions): Promise<Stats | BigIntStats | undefined>;
/**
* @since v19.6.0, v18.15.0
* @return Fulfills with the {fs.StatFs} object for the given `path`.
+12
View File
@@ -1242,10 +1242,14 @@ declare module "node:http2" {
> extends SessionOptions {
streamResetBurst?: number | undefined;
streamResetRate?: number | undefined;
/** @deprecated Use `http1Options.IncomingMessage` instead. */
Http1IncomingMessage?: Http1Request | undefined;
/** @deprecated Use `http1Options.ServerResponse` instead. */
Http1ServerResponse?: Http1Response | undefined;
http1Options?: Http1Options<Http1Request, Http1Response> | undefined;
Http2ServerRequest?: Http2Request | undefined;
Http2ServerResponse?: Http2Response | undefined;
strictSingleValueFields?: boolean | undefined;
}
interface SecureClientSessionOptions extends ClientSessionOptions, tls.ConnectionOptions {}
interface SecureServerSessionOptions<
@@ -1269,6 +1273,14 @@ declare module "node:http2" {
allowHTTP1?: boolean | undefined;
origins?: string[] | undefined;
}
interface Http1Options<
Request extends typeof IncomingMessage,
Response extends typeof ServerResponse<InstanceType<Request>>,
> {
IncomingMessage?: Request | undefined;
ServerResponse?: Response | undefined;
keepAliveTimeout?: number | undefined;
}
interface Http2ServerCommon {
setTimeout(msec?: number, callback?: () => void): this;
/**
+2
View File
@@ -95,6 +95,7 @@
/// <reference path="sqlite.d.ts" />
/// <reference path="stream.d.ts" />
/// <reference path="stream/consumers.d.ts" />
/// <reference path="stream/iter.d.ts" />
/// <reference path="stream/promises.d.ts" />
/// <reference path="stream/web.d.ts" />
/// <reference path="string_decoder.d.ts" />
@@ -113,3 +114,4 @@
/// <reference path="wasi.d.ts" />
/// <reference path="worker_threads.d.ts" />
/// <reference path="zlib.d.ts" />
/// <reference path="zlib/iter.d.ts" />
+5
View File
@@ -2035,6 +2035,9 @@ declare module "node:inspector" {
autoAttach: boolean;
waitForDebuggerOnStart: boolean;
}
interface GetTargetsReturnType {
targetInfos: TargetInfo[];
}
interface TargetCreatedEventDataType {
targetInfo: TargetInfo;
}
@@ -2506,6 +2509,7 @@ declare module "node:inspector" {
*/
post(method: "NodeWorker.detach", params?: NodeWorker.DetachParameterType, callback?: (err: Error | null) => void): void;
post(method: "NodeWorker.detach", callback?: (err: Error | null) => void): void;
post(method: "Target.getTargets", callback?: (err: Error | null, params: Target.GetTargetsReturnType) => void): void;
post(method: "Target.setAutoAttach", params?: Target.SetAutoAttachParameterType, callback?: (err: Error | null) => void): void;
post(method: "Target.setAutoAttach", callback?: (err: Error | null) => void): void;
post(method: "DOMStorage.clear", params?: DOMStorage.ClearParameterType, callback?: (err: Error | null) => void): void;
@@ -3642,6 +3646,7 @@ declare module "node:inspector/promises" {
* Detached from the worker with given sessionId.
*/
post(method: "NodeWorker.detach", params?: NodeWorker.DetachParameterType): Promise<void>;
post(method: "Target.getTargets"): Promise<Target.GetTargetsReturnType>;
post(method: "Target.setAutoAttach", params?: Target.SetAutoAttachParameterType): Promise<void>;
post(method: "DOMStorage.clear", params?: DOMStorage.ClearParameterType): Promise<void>;
/**
+1
View File
@@ -218,6 +218,7 @@ declare module "node:module" {
* This feature requires `--allow-worker` if used with the
* [Permission Model](https://nodejs.org/docs/latest-v25.x/api/permissions.html#permission-model).
* @since v20.6.0, v18.19.0
* @deprecated Use `module.registerHooks()` instead.
* @param specifier Customization hooks to be registered; this should be
* the same string that would be passed to `import()`, except that if it is
* relative, it is resolved relative to `parentURL`.
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@types/node",
"version": "25.6.2",
"version": "25.9.1",
"description": "TypeScript definitions for node",
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/node",
"license": "MIT",
@@ -147,9 +147,9 @@
},
"scripts": {},
"dependencies": {
"undici-types": "~7.19.0"
"undici-types": ">=7.24.0 <7.24.7"
},
"peerDependencies": {},
"typesPublisherContentHash": "89af6b1f98f4dcf78863724bff751d6099486220dae09983e7b6430b0be61ac2",
"typesPublisherContentHash": "2546f5f588e15fc9aa202a3005dab2859d006fd48a8448107741e5ce184e9098",
"typeScriptVersion": "5.3"
}
+54 -25
View File
@@ -822,6 +822,28 @@ declare module "node:process" {
* @since v0.7.0
*/
abort(): never;
/**
* The `process.addUncaughtExceptionCaptureCallback()` function adds a callback
* that will be invoked when an uncaught exception occurs, receiving the exception
* value as its first argument.
*
* Unlike `process.setUncaughtExceptionCaptureCallback()`, this function allows
* multiple callbacks to be registered and does not conflict with the
* [`domain`](https://nodejs.org/docs/latest-v25.x/api/domain.html) module. Callbacks are called in reverse order of registration
* (most recent first). If a callback returns `true`, subsequent callbacks
* and the default uncaught exception handling are skipped.
*
* ```js
* import process from 'node:process';
*
* process.addUncaughtExceptionCaptureCallback((err) => {
* console.error('Caught exception:', err.message);
* return true; // Indicates exception was handled
* });
* ```
* @since v25.9.0
*/
addUncaughtExceptionCaptureCallback(fn: (err: unknown) => boolean): void;
/**
* The `process.chdir()` method changes the current working directory of the
* Node.js process or throws an exception if doing so fails (for instance, if
@@ -1418,9 +1440,11 @@ declare module "node:process" {
* method with a non-`null` argument while another capture function is set will
* throw an error.
*
* Using this function is mutually exclusive with using the deprecated `domain` built-in module.
* To register multiple callbacks that can coexist, use
* `process.addUncaughtExceptionCaptureCallback()` instead.
* @since v9.3.0
*/
// TODO: callback parameter should be `unknown`
setUncaughtExceptionCaptureCallback(cb: ((err: Error) => void) | null): void;
/**
* Indicates whether a callback has been set using {@link setUncaughtExceptionCaptureCallback}.
@@ -1474,30 +1498,35 @@ declare module "node:process" {
* Will generate an object similar to:
*
* ```console
* { node: '20.2.0',
* acorn: '8.8.2',
* ada: '2.4.0',
* ares: '1.19.0',
* base64: '0.5.0',
* brotli: '1.0.9',
* cjs_module_lexer: '1.2.2',
* cldr: '43.0',
* icu: '73.1',
* llhttp: '8.1.0',
* modules: '115',
* napi: '8',
* nghttp2: '1.52.0',
* nghttp3: '0.7.0',
* ngtcp2: '0.8.1',
* openssl: '3.0.8+quic',
* simdutf: '3.2.9',
* tz: '2023c',
* undici: '5.22.0',
* unicode: '15.0',
* uv: '1.44.2',
* uvwasi: '0.0.16',
* v8: '11.3.244.8-node.9',
* zlib: '1.2.13' }
* { node: '26.0.0-pre',
* acorn: '8.15.0',
* ada: '3.4.1',
* amaro: '1.1.5',
* ares: '1.34.6',
* brotli: '1.2.0',
* merve: '1.0.0',
* cldr: '48.0',
* icu: '78.2',
* llhttp: '9.3.0',
* modules: '144',
* napi: '10',
* nbytes: '0.1.1',
* ncrypto: '0.0.1',
* nghttp2: '1.68.0',
* nghttp3: '',
* ngtcp2: '',
* openssl: '3.5.4',
* simdjson: '4.2.4',
* simdutf: '7.3.3',
* sqlite: '3.51.2',
* tz: '2025c',
* undici: '7.18.2',
* unicode: '17.0',
* uv: '1.51.0',
* uvwasi: '0.0.23',
* v8: '14.3.127.18-node.10',
* zlib: '1.3.1-e00f703',
* zstd: '1.5.7' }
* ```
* @since v0.2.0
*/
+2 -2
View File
@@ -179,7 +179,7 @@ declare module "node:quic" {
* The TLS crypto keys to use for sessions.
* @since v23.8.0
*/
keys?: KeyObject | webcrypto.CryptoKey | ReadonlyArray<KeyObject | webcrypto.CryptoKey> | undefined;
keys?: KeyObject | readonly KeyObject[] | undefined;
/**
* Specifies the maximum UDP packet payload size.
* @since v23.8.0
@@ -653,7 +653,7 @@ declare module "node:quic" {
/**
* Sends an unreliable datagram to the remote peer, returning the datagram ID.
* If the datagram payload is specified as an `ArrayBufferView`, then ownership of
* that view will be transfered to the underlying stream.
* that view will be transferred to the underlying stream.
* @since v23.8.0
*/
sendDatagram(datagram: string | NodeJS.ArrayBufferView): bigint;
+15
View File
@@ -86,6 +86,21 @@ declare module "node:repl" {
* @default false
*/
breakEvalOnSigint?: boolean | undefined;
/**
* This function customizes error handling in the REPL.
* It receives the thrown exception as its first argument and must return one
* of the following values synchronously:
* * `'print'` to print the error to the output stream (default behavior).
* * `'ignore'` to skip all remaining error handling.
* * `'unhandled'` to treat the exception as fully unhandled. In this case,
* the error will be passed to process-wide exception handlers, such as
* the `'uncaughtException'` event.
* The `'unhandled'` value may or may not be desirable in situations
* where the `REPLServer` instance has been closed, depending on the particular
* use case.
* @since v25.9.0
*/
handleError?: ((err: unknown) => "print" | "ignore" | "unhandled") | undefined;
}
type REPLEval = (
this: REPLServer,

Some files were not shown because too many files have changed in this diff Show More