You've already forked Pandona-Engine
初始化提交
This commit is contained in:
169
IFLOW.md
Normal file
169
IFLOW.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Pandona Engine (PE) - IFLOW 上下文
|
||||
|
||||
## 项目概述
|
||||
Pandona Engine (PE) 是一个功能完整的 JavaScript 2D 游戏引擎,基于 DOM 实现,用于创建各种类型的 2D 游戏和动画。现在支持现代编译时架构,使用 Vite 作为构建工具。
|
||||
|
||||
## 核心特性
|
||||
1. **完整的游戏开发功能**:支持创建各种类型的2D游戏
|
||||
2. **模块化架构**:核心功能拆分为独立模块,易于扩展和维护
|
||||
3. **插件系统**:支持自定义插件扩展引擎功能
|
||||
4. **多种元素类型**:支持精灵、容器、文本、HTML 和 SVG 元素
|
||||
5. **高级动画系统**:内置补间动画、帧动画、动画序列和时间轴
|
||||
6. **音频管理**:支持音效和背景音乐播放
|
||||
7. **场景管理**:支持多场景切换和过渡效果
|
||||
8. **事件系统**:增强的事件总线,支持全局和局部事件
|
||||
9. **内存管理**:完善的资源清理机制
|
||||
10. **碰撞检测**:矩形碰撞检测系统
|
||||
11. **输入处理**:键盘和鼠标输入处理
|
||||
12. **UI系统**:按钮、标签、图像、滑块等UI组件
|
||||
13. **摄像机系统**:支持跟随、缩放、旋转和震动效果
|
||||
14. **粒子系统**:创建各种视觉效果
|
||||
15. **组件系统**:基于组件的游戏对象系统
|
||||
16. **游戏循环**:固定时间步长的游戏循环
|
||||
17. **编译时架构**:使用 Vite 构建工具,支持热重载和代码优化
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
cssEngine/
|
||||
├── index.html # 主页面
|
||||
├── main.js # 应用入口文件
|
||||
├── vite.config.js # Vite配置文件
|
||||
├── package.json # 项目配置
|
||||
├── README.md # 项目说明文档
|
||||
├── IFLOW.md # IFLOW上下文文件
|
||||
├── public/ # 静态资源
|
||||
│ └── sprite.css # 精灵样式文件
|
||||
├── style/ # 全局样式
|
||||
│ └── base.less # 基础样式
|
||||
├── examples/ # 示例项目
|
||||
│ ├── spaceShooter.js # 太空射击游戏示例
|
||||
│ └── spaceShooter.html # 示例游戏HTML文件
|
||||
├── src/
|
||||
│ ├── core/ # 核心模块
|
||||
│ │ └── Engine.js # 引擎主类
|
||||
│ ├── elements/ # 元素类
|
||||
│ │ ├── BaseElement.js
|
||||
│ │ ├── Sprite.js
|
||||
│ │ ├── Box.js
|
||||
│ │ ├── TextElement.js
|
||||
│ │ ├── HtmlElement.js
|
||||
│ │ ├── SvgElement.js
|
||||
│ │ ├── GameObject.js
|
||||
│ │ └── Component.js
|
||||
│ ├── managers/ # 管理器
|
||||
│ │ ├── ResourceManager.js
|
||||
│ │ ├── SceneManager.js
|
||||
│ │ ├── AudioManager.js
|
||||
│ │ ├── TransitionManager.js
|
||||
│ │ └── Camera.js
|
||||
│ ├── animation/ # 动画系统
|
||||
│ │ ├── Tween.js
|
||||
│ │ ├── AnimationSystem.js
|
||||
│ │ └── AnimationController.js
|
||||
│ ├── effects/ # 特效系统
|
||||
│ │ └── ParticleSystem.js
|
||||
│ ├── ui/ # UI系统
|
||||
│ │ └── UI.js
|
||||
│ ├── utils/ # 工具类
|
||||
│ │ └── EventBus.js # 事件总线
|
||||
│ └── scenes/ # 场景目录
|
||||
│ └── index/ # 主场景
|
||||
│ ├── index.js # 场景结构和逻辑
|
||||
│ └── index.less # 场景样式
|
||||
└── test/ # 测试文件
|
||||
└── ... # 各模块测试
|
||||
```
|
||||
|
||||
## 核心类和API
|
||||
|
||||
### Engine 引擎主类
|
||||
- `constructor(element, options)` - 创建引擎实例
|
||||
- `use(plugin, options)` - 安装插件
|
||||
- `load(src)` - 加载资源
|
||||
- `loadSound(name, src, options)` - 加载音效
|
||||
- `loadMusic(name, src, options)` - 加载音乐
|
||||
- `playSound(name, options)` - 播放音效
|
||||
- `playMusic(name, options)` - 播放音乐
|
||||
- `createScene(name)` - 创建场景
|
||||
- `switchScene(name)` - 切换场景
|
||||
- `tween(target, duration, easing)` - 创建补间动画
|
||||
- `createFrameAnimation(name, frames, frameRate)` - 创建帧动画
|
||||
- `playFrameAnimation(sprite, animationName, loop)` - 播放帧动画
|
||||
- `addGameObject(obj)` - 添加游戏对象
|
||||
- `removeGameObject(obj)` - 移除游戏对象
|
||||
- `checkCollision(obj1, obj2)` - 碰撞检测
|
||||
- `setCameraPosition(x, y)` - 设置摄像机位置
|
||||
- `follow(target, offset)` - 跟随目标
|
||||
- `setCameraZoom(zoom)` - 设置摄像机缩放
|
||||
- `shakeCamera(intensity, duration)` - 屏幕震动
|
||||
- `addUIElement(element)` - 添加UI元素
|
||||
- `removeUIElement(element)` - 移除UI元素
|
||||
|
||||
### GameObject 游戏对象基类
|
||||
- `setPosition(x, y)` - 设置位置
|
||||
- `setSize(width, height)` - 设置尺寸
|
||||
- `setRotation(rotation)` - 设置旋转角度
|
||||
- `setScale(scaleX, scaleY)` - 设置缩放
|
||||
- `setVisible(visible)` - 显示/隐藏
|
||||
- `addChild(child)` - 添加子对象
|
||||
- `removeChild(child)` - 移除子对象
|
||||
- `addComponent(name, component)` - 添加组件
|
||||
- `getComponent(name)` - 获取组件
|
||||
- `removeComponent(name)` - 移除组件
|
||||
|
||||
### Component 组件基类
|
||||
- `onAdd(gameObject)` - 当组件被添加到游戏对象时调用
|
||||
- `onRemove(gameObject)` - 当组件从游戏对象中移除时调用
|
||||
- `update(deltaTime)` - 更新方法
|
||||
- `onDestroy(gameObject)` - 销毁方法
|
||||
|
||||
### 预定义组件
|
||||
- `PhysicsComponent` - 物理组件
|
||||
- `ColliderComponent` - 碰撞组件
|
||||
- `AnimationComponent` - 动画组件
|
||||
- `InputComponent` - 输入组件
|
||||
- `LifecycleComponent` - 生命周期组件
|
||||
|
||||
### UI组件
|
||||
- `UIButton` - 按钮
|
||||
- `UILabel` - 标签
|
||||
- `UIImage` - 图像
|
||||
- `UISlider` - 滑块
|
||||
|
||||
## 编译时架构
|
||||
|
||||
### 构建工具
|
||||
- 使用 Vite 作为构建工具
|
||||
- 支持 ES6 模块系统
|
||||
- 支持 Less CSS 预处理器
|
||||
- 支持代码压缩和优化
|
||||
- 支持开发服务器热重载
|
||||
|
||||
### 开发命令
|
||||
```bash
|
||||
# 启动开发服务器(热重载)
|
||||
npm run dev
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 预览构建结果
|
||||
npm run preview
|
||||
```
|
||||
|
||||
### 场景化开发
|
||||
- 使用 `src/scenes/` 目录组织不同场景
|
||||
- 每个场景包含 `index.js`(场景逻辑)和 `index.less`(场景样式)
|
||||
- 支持类似HTML的标签语法定义场景结构
|
||||
|
||||
## 开发约定
|
||||
1. 使用ES6模块系统
|
||||
2. 遵循面向对象编程原则
|
||||
3. 使用JSDoc注释重要函数和类
|
||||
4. 保持代码简洁和可读性
|
||||
5. 遵循现有的代码风格和命名约定
|
||||
6. 使用 Less 作为 CSS 预处理器
|
||||
7. 遵循场景化组织结构
|
||||
|
||||
## 示例项目
|
||||
项目包含一个完整的太空射击游戏示例,展示了引擎的各种功能,位于 `examples/spaceShooter.js` 和 `examples/spaceShooter.html`。
|
||||
889
README.md
889
README.md
@@ -1,20 +1,107 @@
|
||||
# DOM 渲染引擎
|
||||
# Pandona Engine (PE)
|
||||
|
||||
这个轻量级 JavaScript 渲染引擎使用 DOM 元素创建 2D 场景,支持精灵、容器、文本、HTML 和 SVG 等元素,提供简单直观的 API 进行场景管理。
|
||||
一个功能完整的 JavaScript 2D 游戏引擎,基于 DOM 实现,用于创建各种类型的 2D 游戏和动画。
|
||||
|
||||
## 功能特性
|
||||
## 编译时架构
|
||||
|
||||
- 🎭 创建可自定义尺寸的舞台容器
|
||||
- 🖼️ 支持加载和显示图像精灵
|
||||
- 📦 创建容器元素用于分组管理
|
||||
- ✏️ 文本元素创建和样式设置
|
||||
- 🌐 支持原生 HTML 内容嵌入
|
||||
- 🎨 SVG 矢量图形支持
|
||||
- 📍 精确控制元素位置和尺寸
|
||||
- 🎭 简单的事件绑定机制
|
||||
Pandona Engine 现在支持现代编译时架构,使用 Vite 作为构建工具,支持:
|
||||
- ES6 模块系统
|
||||
- Less CSS 预处理器
|
||||
- 代码压缩和优化
|
||||
- 开发服务器热重载
|
||||
- 场景化组织结构
|
||||
|
||||
## 简化版API (推荐)
|
||||
|
||||
为了让开发者更容易上手,Pandona Engine提供了简化版API,参考了PixiJS、Egret和Vue 3的设计理念,让代码更加简洁易读。
|
||||
|
||||
## 特性
|
||||
|
||||
- 🎮 **完整的游戏开发功能**:支持创建各种类型的2D游戏
|
||||
- 🌟 **模块化架构**:核心功能拆分为独立模块,易于扩展和维护
|
||||
- 🌟 **插件系统**:支持自定义插件扩展引擎功能
|
||||
- 🎨 **多种元素类型**:支持精灵、容器、文本、HTML 和 SVG 元素
|
||||
- 🌈 **高级动画系统**:内置补间动画、帧动画、动画序列和时间轴
|
||||
- 🎵 **音频管理**:支持音效和背景音乐播放
|
||||
- 🌍 **场景管理**:支持多场景切换和过渡效果
|
||||
- 📡 **事件系统**:增强的事件总线,支持全局和局部事件
|
||||
- 🧹 **内存管理**:完善的资源清理机制
|
||||
- 🎯 **碰撞检测**:矩形碰撞检测系统
|
||||
- 🎮 **输入处理**:键盘和鼠标输入处理
|
||||
- 📱 **UI系统**:按钮、标签、图像、滑块等UI组件
|
||||
- 🎥 **摄像机系统**:支持跟随、缩放、旋转和震动效果
|
||||
- ✨ **粒子系统**:创建各种视觉效果
|
||||
- ⚙️ **组件系统**:基于组件的游戏对象系统
|
||||
- 📈 **游戏循环**:固定时间步长的游戏循环
|
||||
|
||||
## 安装
|
||||
|
||||
```bash
|
||||
# 克隆项目
|
||||
git clone <repository-url>
|
||||
|
||||
# 安装依赖
|
||||
npm install
|
||||
```
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 开发模式
|
||||
|
||||
```bash
|
||||
# 启动开发服务器
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 构建项目
|
||||
|
||||
```bash
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 预览构建结果
|
||||
npm run preview
|
||||
```
|
||||
|
||||
### 简化版API用法 (推荐)
|
||||
|
||||
```javascript
|
||||
// 创建引擎实例
|
||||
const game = PE.createEngine('#game-container', {
|
||||
width: 800,
|
||||
height: 600,
|
||||
background: '#f0f0f0'
|
||||
});
|
||||
|
||||
// 加载资源
|
||||
game.assets.load('character.png')
|
||||
.then(img => {
|
||||
// 创建精灵 (链式调用)
|
||||
const player = game.create('sprite', {
|
||||
image: img,
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50
|
||||
}).position(100, 100)
|
||||
.size(50, 50)
|
||||
.on('click', () => {
|
||||
player.position(200, 150);
|
||||
});
|
||||
|
||||
// 添加到舞台
|
||||
game.stage.add(player);
|
||||
|
||||
// 创建移动动画
|
||||
game.animate(player, { x: 300, y: 200 }, 1000, {
|
||||
easing: 'easeInOutQuad',
|
||||
onComplete: () => {
|
||||
console.log('动画完成!');
|
||||
}
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 基本用法
|
||||
|
||||
```javascript
|
||||
@@ -26,10 +113,10 @@ const game = new Engine('#game-container', {
|
||||
});
|
||||
|
||||
// 加载资源
|
||||
game.Load('character.png')
|
||||
game.load('character.png')
|
||||
.then(img => {
|
||||
// 创建精灵
|
||||
const player = game.CreateSprite(img, 100, 100, 50, 50);
|
||||
const player = game.createSprite(img, 100, 100, 50, 50);
|
||||
|
||||
// 添加到舞台
|
||||
game.stage.add(player);
|
||||
@@ -41,60 +128,465 @@ game.Load('character.png')
|
||||
});
|
||||
```
|
||||
|
||||
### 使用动画系统
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 创建移动动画
|
||||
game.animate(player, { x: 300, y: 200 }, 1000, {
|
||||
easing: 'easeInOutQuad',
|
||||
onUpdate: (progress) => {
|
||||
console.log(`动画进度: ${Math.round(progress * 100)}%`);
|
||||
},
|
||||
onComplete: () => {
|
||||
console.log('动画完成!');
|
||||
}
|
||||
});
|
||||
|
||||
// 创建帧动画
|
||||
const walkAnimation = game.animate.frame(player, [
|
||||
'walk1.png', 'walk2.png', 'walk3.png'
|
||||
], 10, { loop: true });
|
||||
|
||||
// 播放帧动画
|
||||
walkAnimation.play();
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 创建移动动画
|
||||
game.tween(player, 1000, 'easeInOutQuad')
|
||||
.to({ x: 300, y: 200 })
|
||||
.onUpdate(progress => {
|
||||
console.log(`动画进度: ${Math.round(progress * 100)}%`);
|
||||
})
|
||||
.onComplete(() => {
|
||||
console.log('动画完成!');
|
||||
})
|
||||
.start();
|
||||
```
|
||||
|
||||
### 使用场景管理
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 创建场景
|
||||
const menuScene = game.scene.create('menu');
|
||||
const gameScene = game.scene.create('game');
|
||||
|
||||
// 切换场景
|
||||
game.scene.switch('menu');
|
||||
|
||||
// 带过渡效果的场景切换
|
||||
game.scene.switch('game', {
|
||||
transition: {
|
||||
type: 'fade',
|
||||
duration: 1000
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 创建场景
|
||||
const menuScene = game.createScene('menu');
|
||||
const gameScene = game.createScene('game');
|
||||
|
||||
// 切换场景
|
||||
game.switchScene('menu');
|
||||
```
|
||||
|
||||
## API 参考
|
||||
|
||||
### 引擎初始化
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
const engine = PE.createEngine(elementSelector, options);
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
const engine = new Engine(elementSelector, options);
|
||||
```
|
||||
|
||||
| 参数 | 类型 | 默认值 | 说明 |
|
||||
|------|------|---------|------|
|
||||
| `elementSelector` | string | `'body'` | 挂载舞台的 DOM 选择器 |
|
||||
| `options.width` | number | 800 | 舞台宽度(px) |
|
||||
| `options.height` | number | 600 | 舞台高度(px) |
|
||||
| `options.background` | string | `'transparent'` | 舞台背景色 |
|
||||
| `options.fps` | number | 60 | 游戏循环帧率 |
|
||||
|
||||
### 插件系统
|
||||
```javascript
|
||||
// 安装插件
|
||||
engine.use(YourPlugin, options);
|
||||
```
|
||||
|
||||
### 资源加载
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
engine.Load(imageUrl)
|
||||
// 加载单个资源
|
||||
game.assets.load(imageUrl)
|
||||
.then(img => { /* 使用图像 */ })
|
||||
.catch(error => { /* 处理错误 */ });
|
||||
|
||||
// 批量加载资源
|
||||
game.assets.load([imageUrl1, imageUrl2, imageUrl3])
|
||||
.then(resources => { /* 使用资源 */ })
|
||||
.catch(error => { /* 处理错误 */ });
|
||||
|
||||
// 预加载资源并显示进度
|
||||
game.assets.preload([
|
||||
'image1.png',
|
||||
'image2.png',
|
||||
'sound1.wav'
|
||||
], (progress, loaded, total) => {
|
||||
console.log(`加载进度: ${Math.round(progress * 100)}% (${loaded}/${total})`);
|
||||
}).then(() => {
|
||||
console.log('所有资源加载完成!');
|
||||
});
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
engine.load(imageUrl)
|
||||
.then(img => { /* 使用图像 */ })
|
||||
.catch(error => { /* 处理错误 */ });
|
||||
```
|
||||
|
||||
### 音频管理
|
||||
```javascript
|
||||
// 加载音效
|
||||
engine.loadSound('shoot', 'sounds/shoot.wav');
|
||||
|
||||
// 播放音效
|
||||
engine.playSound('shoot');
|
||||
|
||||
// 加载音乐
|
||||
engine.loadMusic('background', 'sounds/bg.mp3');
|
||||
|
||||
// 播放音乐
|
||||
engine.playMusic('background', { loop: true });
|
||||
```
|
||||
|
||||
### 动画系统
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 创建补间动画
|
||||
game.animate(target, { x: 100, y: 200 }, 1000, {
|
||||
easing: 'easeInOutQuad',
|
||||
delay: 500,
|
||||
repeat: 2,
|
||||
yoyo: true,
|
||||
onUpdate: (progress) => { /* 更新回调 */ },
|
||||
onComplete: () => { /* 完成回调 */ }
|
||||
});
|
||||
|
||||
// 创建并行动画
|
||||
const parallelAnimation = game.animate.parallel([
|
||||
game.animate(target1, { x: 100 }, 1000),
|
||||
game.animate(target2, { y: 200 }, 1000)
|
||||
]);
|
||||
|
||||
parallelAnimation.play();
|
||||
|
||||
// 创建链式动画
|
||||
const chainAnimation = game.animate.chain([
|
||||
game.animate(target, { x: 100 }, 1000),
|
||||
game.animate(target, { y: 200 }, 1000)
|
||||
]);
|
||||
|
||||
chainAnimation.play();
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 创建补间动画
|
||||
engine.tween(target, duration, easing)
|
||||
.to({ x: 100, y: 200 })
|
||||
.onUpdate(callback)
|
||||
.onComplete(callback)
|
||||
.start();
|
||||
|
||||
// 创建帧动画
|
||||
engine.createFrameAnimation('walk', [
|
||||
'walk1.png', 'walk2.png', 'walk3.png'
|
||||
], 10);
|
||||
|
||||
// 播放帧动画
|
||||
engine.playFrameAnimation(sprite, 'walk', true);
|
||||
```
|
||||
|
||||
支持的缓动函数:
|
||||
- `linear`
|
||||
- `easeInQuad`
|
||||
- `easeOutQuad`
|
||||
- `easeInOutQuad`
|
||||
- `easeInCubic`
|
||||
- `easeOutCubic`
|
||||
- `easeInOutCubic`
|
||||
- `easeInQuart`
|
||||
- `easeOutQuart`
|
||||
- `easeInOutQuart`
|
||||
- `easeInQuint`
|
||||
- `easeOutQuint`
|
||||
- `easeInOutQuint`
|
||||
- `easeInSine`
|
||||
- `easeOutSine`
|
||||
- `easeInOutSine`
|
||||
- `easeInExpo`
|
||||
- `easeOutExpo`
|
||||
- `easeInOutExpo`
|
||||
- `easeInCirc`
|
||||
- `easeOutCirc`
|
||||
- `easeInOutCirc`
|
||||
- `easeInBack`
|
||||
- `easeOutBack`
|
||||
- `easeInOutBack`
|
||||
- `easeInElastic`
|
||||
- `easeOutElastic`
|
||||
- `easeInOutElastic`
|
||||
- `easeInBounce`
|
||||
- `easeOutBounce`
|
||||
- `easeInOutBounce`
|
||||
|
||||
### 场景管理
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 创建场景
|
||||
const scene = engine.scene.create(name);
|
||||
|
||||
// 切换场景
|
||||
engine.scene.switch(name);
|
||||
|
||||
// 场景过渡效果
|
||||
engine.scene.transition.fade('game', 1000);
|
||||
engine.scene.transition.slide('game', 'left', 500);
|
||||
engine.scene.transition.zoom('game', 1000);
|
||||
engine.scene.transition.flip('game', 1000);
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 创建场景
|
||||
const scene = engine.createScene(name);
|
||||
|
||||
// 切换场景
|
||||
engine.switchScene(name);
|
||||
|
||||
// 场景过渡效果
|
||||
engine.transitionFade('game', 1000);
|
||||
engine.transitionSlide('game', 'left', 500);
|
||||
```
|
||||
|
||||
### 摄像机系统
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 设置摄像机位置 (带动画)
|
||||
engine.camera.move(400, 300, 1000).then(() => {
|
||||
console.log('摄像机移动完成');
|
||||
});
|
||||
|
||||
// 跟随目标
|
||||
engine.camera.follow(player, { x: 0, y: 100 });
|
||||
|
||||
// 摄像机缩放 (带动画)
|
||||
engine.camera.zoom(1.5, 1000).then(() => {
|
||||
console.log('摄像机缩放完成');
|
||||
});
|
||||
|
||||
// 摄像机旋转 (带动画)
|
||||
engine.camera.rotate(PE.PI, 1000).then(() => {
|
||||
console.log('摄像机旋转完成');
|
||||
});
|
||||
|
||||
// 屏幕震动
|
||||
engine.camera.shake(10, 500);
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 设置摄像机位置
|
||||
engine.setCameraPosition(400, 300);
|
||||
|
||||
// 跟随目标
|
||||
engine.follow(player, { x: 0, y: 100 });
|
||||
|
||||
// 摄像机缩放
|
||||
engine.setCameraZoom(1.5);
|
||||
|
||||
// 屏幕震动
|
||||
engine.shakeCamera(10, 500);
|
||||
```
|
||||
|
||||
### UI系统
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 创建按钮 (链式调用)
|
||||
const button = engine.ui.create('button', {
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 200,
|
||||
height: 50,
|
||||
text: '点击我'
|
||||
}).position(100, 100)
|
||||
.size(200, 50)
|
||||
.background('#007acc')
|
||||
.hover('#005a99')
|
||||
.pressed('#003d66')
|
||||
.color('#ffffff')
|
||||
.on('click', () => {
|
||||
console.log('按钮被点击了!');
|
||||
});
|
||||
|
||||
engine.ui.add(button);
|
||||
|
||||
// 创建标签 (链式调用)
|
||||
const label = engine.ui.create('label', {
|
||||
x: 100,
|
||||
y: 200,
|
||||
text: 'Hello World'
|
||||
}).position(100, 200)
|
||||
.text('Hello World')
|
||||
.font('20px Arial')
|
||||
.color('#ffffff');
|
||||
|
||||
engine.ui.add(label);
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 创建按钮
|
||||
const button = new UIButton(100, 100, 200, 50, '点击我');
|
||||
button.on('click', () => {
|
||||
console.log('按钮被点击了!');
|
||||
});
|
||||
engine.addUIElement(button);
|
||||
|
||||
// 创建标签
|
||||
const label = new UILabel(100, 200, 'Hello World');
|
||||
engine.addUIElement(label);
|
||||
```
|
||||
|
||||
### 创建元素
|
||||
|
||||
#### 精灵 (CreateSprite)
|
||||
#### 简化版API
|
||||
```javascript
|
||||
const sprite = engine.CreateSprite(imgElement, x, y, width, height);
|
||||
// 创建精灵 (链式调用)
|
||||
const sprite = engine.create('sprite', {
|
||||
image: imgElement,
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50
|
||||
}).position(100, 100)
|
||||
.size(50, 50)
|
||||
.alpha(0.8)
|
||||
.scale(1.2)
|
||||
.rotate(PE.PI_2)
|
||||
.on('click', () => {
|
||||
console.log('精灵被点击了!');
|
||||
});
|
||||
|
||||
// 创建容器 (链式调用)
|
||||
const container = game.create('box', {
|
||||
x: 50,
|
||||
y: 50,
|
||||
width: 200,
|
||||
height: 200
|
||||
}).position(50, 50)
|
||||
.size(200, 200)
|
||||
.addChild(sprite);
|
||||
|
||||
// 创建文本 (链式调用)
|
||||
const text = game.create('text', {
|
||||
text: 'Hello World',
|
||||
x: 100,
|
||||
y: 100
|
||||
}).position(100, 100)
|
||||
.text('Hello World')
|
||||
.font('bold 24px Arial')
|
||||
.color('#ff0000')
|
||||
.align('center');
|
||||
|
||||
// 创建HTML元素 (链式调用)
|
||||
const html = game.create('html', {
|
||||
html: '<button>Click</button>',
|
||||
x: 300,
|
||||
y: 200
|
||||
}).position(300, 200)
|
||||
.html('<button>Click</button>');
|
||||
|
||||
// 创建SVG元素 (链式调用)
|
||||
const svg = game.create('svg', {
|
||||
x: 400,
|
||||
y: 300,
|
||||
width: 100,
|
||||
height: 100,
|
||||
content: '<circle cx="50" cy="50" r="40"/>'
|
||||
}).position(400, 300)
|
||||
.size(100, 100)
|
||||
.content('<circle cx="50" cy="50" r="40"/>');
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
|
||||
##### 精灵 (createSprite)
|
||||
```javascript
|
||||
const sprite = engine.createSprite(imgElement, x, y, width, height);
|
||||
```
|
||||
- 支持位置和尺寸控制
|
||||
- 支持事件绑定
|
||||
|
||||
#### 容器 (CreateBox)
|
||||
##### 容器 (createBox)
|
||||
```javascript
|
||||
const container = engine.CreateBox(x, y, width, height);
|
||||
const container = engine.createBox(x, y, width, height);
|
||||
```
|
||||
- 用于元素分组管理
|
||||
- 支持嵌套结构
|
||||
|
||||
#### 文本 (CreateText)
|
||||
##### 文本 (createText)
|
||||
```javascript
|
||||
const text = engine.CreateText('Hello', 50, 50);
|
||||
const text = engine.createText('Hello', 50, 50);
|
||||
text.setColor('#ff0000');
|
||||
text.setFont('bold 24px Arial');
|
||||
```
|
||||
|
||||
#### HTML 元素 (CreateHtml)
|
||||
##### HTML 元素 (createHtml)
|
||||
```javascript
|
||||
const html = engine.CreateHtml('<button>Click</button>', 300, 200);
|
||||
const html = engine.createHtml('<button>Click</button>', 300, 200);
|
||||
```
|
||||
|
||||
#### SVG 元素 (CreateSvg)
|
||||
##### SVG 元素 (createSvg)
|
||||
```javascript
|
||||
const svg = engine.CreateSvg(400, 300, 100, 100, '<circle cx="50" cy="50" r="40"/>');
|
||||
const svg = engine.createSvg(400, 300, 100, 100, '<circle cx="50" cy="50" r="40"/>');
|
||||
```
|
||||
|
||||
### 元素通用方法
|
||||
|
||||
#### 简化版API
|
||||
所有创建的元素支持以下链式调用方法:
|
||||
|
||||
| 方法 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| `position(x, y)` | 设置元素位置 | `sprite.position(150, 200)` |
|
||||
| `size(width, height)` | 设置元素尺寸 | `box.size(100, 80)` |
|
||||
| `alpha(value)` | 设置透明度 | `sprite.alpha(0.8)` |
|
||||
| `scale(x, y)` | 设置缩放 | `sprite.scale(1.2, 1.2)` |
|
||||
| `rotate(angle)` | 设置旋转 | `sprite.rotate(PE.PI_2)` |
|
||||
| `add(child)` | 添加子元素 | `container.add(sprite)` |
|
||||
| `remove(child)` | 移除子元素 | `container.remove(sprite)` |
|
||||
| `on(event, callback)` | 绑定事件 | `sprite.on('click', handleClick)` |
|
||||
| `visible(visible)` | 显示/隐藏元素 | `sprite.visible(false)` |
|
||||
|
||||
#### 基本用法
|
||||
所有创建的元素支持以下方法:
|
||||
|
||||
| 方法 | 说明 | 示例 |
|
||||
@@ -109,57 +601,342 @@ const svg = engine.CreateSvg(400, 300, 100, 100, '<circle cx="50" cy="50" r="40"
|
||||
| `hide()` | 隐藏元素 | `sprite.hide()` |
|
||||
| `show()` | 显示元素 | `sprite.show()` |
|
||||
|
||||
### 游戏对象系统
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 创建游戏对象 (链式调用)
|
||||
const player = engine.gameobject.create({
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50,
|
||||
name: 'player',
|
||||
components: {
|
||||
physics: PE.components.physics({
|
||||
velocityX: 100,
|
||||
velocityY: 0
|
||||
}),
|
||||
collider: PE.components.collider({
|
||||
width: 50,
|
||||
height: 50
|
||||
})
|
||||
},
|
||||
events: {
|
||||
update: (deltaTime) => {
|
||||
// 更新逻辑
|
||||
}
|
||||
}
|
||||
}).position(100, 100)
|
||||
.size(50, 50)
|
||||
.addComponent('animation', PE.components.animation())
|
||||
.on('update', (deltaTime) => {
|
||||
// 更新逻辑
|
||||
});
|
||||
|
||||
// 添加到引擎
|
||||
engine.addGameObject(player);
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 创建游戏对象
|
||||
const player = new GameObject(100, 100, 50, 50);
|
||||
|
||||
// 添加组件
|
||||
player.addComponent('physics', new PhysicsComponent({
|
||||
velocityX: 100,
|
||||
velocityY: 0
|
||||
}));
|
||||
|
||||
player.addComponent('collider', new ColliderComponent({
|
||||
width: 50,
|
||||
height: 50
|
||||
}));
|
||||
|
||||
// 添加到引擎
|
||||
engine.addGameObject(player);
|
||||
```
|
||||
|
||||
### 碰撞检测
|
||||
```javascript
|
||||
// 检查两个对象是否碰撞
|
||||
if (engine.checkCollision(player, enemy)) {
|
||||
console.log('发生碰撞!');
|
||||
}
|
||||
```
|
||||
|
||||
### 音频系统
|
||||
|
||||
#### 简化版API
|
||||
```javascript
|
||||
// 加载音频
|
||||
engine.sound.load('shoot', 'sounds/shoot.wav');
|
||||
engine.sound.load('background', 'sounds/bg.mp3', { type: 'music' });
|
||||
|
||||
// 播放音频
|
||||
engine.sound.play('shoot');
|
||||
engine.sound.play('background', { loop: true, type: 'music' });
|
||||
|
||||
// 控制音量
|
||||
engine.sound.volume(0.5, 'master'); // 主音量
|
||||
engine.sound.volume(0.8, 'sound'); // 音效音量
|
||||
engine.sound.volume(0.6, 'music'); // 音乐音量
|
||||
|
||||
// 停止音频
|
||||
engine.sound.stop('background', 'music');
|
||||
|
||||
// 暂停/恢复音频
|
||||
engine.sound.pause('background', 'music');
|
||||
engine.sound.resume('background', 'music');
|
||||
```
|
||||
|
||||
#### 基本用法
|
||||
```javascript
|
||||
// 加载音效
|
||||
engine.loadSound('shoot', 'sounds/shoot.wav');
|
||||
|
||||
// 播放音效
|
||||
engine.playSound('shoot');
|
||||
|
||||
// 加载音乐
|
||||
engine.loadMusic('background', 'sounds/bg.mp3');
|
||||
|
||||
// 播放音乐
|
||||
engine.playMusic('background', { loop: true });
|
||||
```
|
||||
|
||||
### 销毁引擎
|
||||
```javascript
|
||||
engine.Destroy();
|
||||
engine.destroy();
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
cssEngine/
|
||||
├── index.html # 主页面
|
||||
├── main.js # 应用入口文件
|
||||
├── vite.config.js # Vite配置文件
|
||||
├── package.json # 项目配置
|
||||
├── README.md # 项目说明文档
|
||||
├── public/ # 静态资源
|
||||
│ └── sprite.css # 精灵样式文件
|
||||
├── style/ # 全局样式
|
||||
│ └── base.less # 基础样式
|
||||
├── examples/ # 示例项目
|
||||
│ ├── spaceShooter.js # 太空射击游戏示例
|
||||
│ └── spaceShooter.html # 示例游戏HTML文件
|
||||
├── src/
|
||||
│ ├── core/ # 核心模块
|
||||
│ │ ├── Engine.js # 引擎主类
|
||||
│ │ └── SimplifiedEngine.js # 简化版引擎API
|
||||
│ ├── elements/ # 元素类
|
||||
│ │ ├── BaseElement.js
|
||||
│ │ ├── Sprite.js
|
||||
│ │ ├── Box.js
|
||||
│ │ ├── TextElement.js
|
||||
│ │ ├── HtmlElement.js
|
||||
│ │ ├── SvgElement.js
|
||||
│ │ ├── GameObject.js
|
||||
│ │ ├── Component.js
|
||||
│ │ ├── SimplifiedElements.js # 简化版元素API
|
||||
│ │ ├── SimplifiedGameObject.js # 简化版游戏对象API
|
||||
│ │ └── SimplifiedComponent.js # 简化版组件API
|
||||
│ ├── managers/ # 管理器
|
||||
│ │ ├── ResourceManager.js
|
||||
│ │ ├── SceneManager.js
|
||||
│ │ ├── AudioManager.js
|
||||
│ │ ├── TransitionManager.js
|
||||
│ │ ├── Camera.js
|
||||
│ │ ├── SimplifiedResourceManager.js # 简化版资源管理API
|
||||
│ │ ├── SimplifiedSceneManager.js # 简化版场景管理API
|
||||
│ │ ├── SimplifiedAudioManager.js # 简化版音频管理API
|
||||
│ │ └── SimplifiedCamera.js # 简化版摄像机API
|
||||
│ ├── animation/ # 动画系统
|
||||
│ │ ├── Tween.js
|
||||
│ │ ├── AnimationSystem.js
|
||||
│ │ ├── AnimationController.js
|
||||
│ │ └── SimplifiedAnimation.js # 简化版动画API
|
||||
│ ├── effects/ # 特效系统
|
||||
│ │ ├── ParticleSystem.js
|
||||
│ │ └── SimplifiedParticleSystem.js # 简化版粒子系统API
|
||||
│ ├── ui/ # UI系统
|
||||
│ │ ├── UI.js
|
||||
│ │ └── SimplifiedUI.js # 简化版UI系统API
|
||||
│ ├── utils/ # 工具类
|
||||
│ │ ├── EventBus.js
|
||||
│ │ └── SimplifiedEventBus.js # 简化版事件系统API
|
||||
│ └── scenes/ # 场景目录
|
||||
│ └── index/ # 主场景
|
||||
│ ├── index.js # 场景结构和逻辑
|
||||
│ └── index.less # 场景样式
|
||||
└── test/ # 测试文件
|
||||
└── ... # 各模块测试
|
||||
```
|
||||
|
||||
## 开发指南
|
||||
|
||||
### 编译时架构开发指南
|
||||
|
||||
Pandona Engine 现在支持现代编译时架构,使用 Vite 作为构建工具:
|
||||
|
||||
```bash
|
||||
# 启动开发服务器(热重载)
|
||||
npm run dev
|
||||
|
||||
# 构建生产版本
|
||||
npm run build
|
||||
|
||||
# 预览构建结果
|
||||
npm run preview
|
||||
```
|
||||
|
||||
### 场景化开发
|
||||
|
||||
使用场景化组织结构开发应用:
|
||||
|
||||
```
|
||||
src/scenes/
|
||||
├── index/ # 主场景
|
||||
│ ├── index.js # 场景结构和逻辑
|
||||
│ └── index.less # 场景样式
|
||||
└── other-scene/ # 其他场景
|
||||
├── index.js
|
||||
└── index.less
|
||||
```
|
||||
|
||||
### 简化版API开发指南
|
||||
|
||||
简化版API提供了更简洁的开发方式,推荐新项目使用:
|
||||
|
||||
### 创建游戏角色
|
||||
```javascript
|
||||
const game = new Engine('#game', {
|
||||
width: 1024,
|
||||
height: 768
|
||||
// 使用简化版API创建游戏
|
||||
const game = PE.createEngine('#game-container', {
|
||||
width: 800,
|
||||
height: 600,
|
||||
background: '#000022'
|
||||
});
|
||||
|
||||
game.Load('player.png').then(playerImg => {
|
||||
const player = game.CreateSprite(playerImg, 512, 384, 64, 64);
|
||||
|
||||
// 添加角色名标签
|
||||
const nameTag = game.CreateText('Player 1', 0, -20);
|
||||
nameTag.setColor('gold');
|
||||
nameTag.setFont('bold 14px sans-serif');
|
||||
|
||||
player.add(nameTag);
|
||||
game.stage.add(player);
|
||||
// 使用链式调用创建和配置元素
|
||||
const player = game.create('sprite', {
|
||||
image: playerImage,
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50
|
||||
}).position(100, 100)
|
||||
.size(50, 50)
|
||||
.on('click', () => {
|
||||
console.log('Player clicked!');
|
||||
});
|
||||
|
||||
// 添加到舞台
|
||||
game.stage.add(player);
|
||||
|
||||
// 创建动画
|
||||
game.animate(player, { x: 300, y: 200 }, 1000, {
|
||||
easing: 'easeInOutQuad',
|
||||
onComplete: () => {
|
||||
console.log('Animation completed!');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### 创建 UI 面板
|
||||
### 扩展功能
|
||||
|
||||
可以通过插件系统扩展引擎功能:
|
||||
|
||||
```javascript
|
||||
const panel = game.CreateBox(50, 50, 200, 300);
|
||||
panel.setStyle('background: rgba(0,0,0,0.7); border-radius: 10px;');
|
||||
// 定义插件
|
||||
const MyPlugin = {
|
||||
name: 'MyPlugin',
|
||||
install(engine, options) {
|
||||
// 扩展引擎功能
|
||||
engine.myMethod = () => {
|
||||
console.log('This is my custom method');
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const title = game.CreateText('控制面板', 20, 20);
|
||||
title.setStyle('font-size: 20px; color: white;');
|
||||
|
||||
const button = game.CreateHtml(
|
||||
'<button style="padding: 8px 16px; background: blue; color: white;">开始</button>',
|
||||
50, 80
|
||||
);
|
||||
|
||||
panel.add(title);
|
||||
panel.add(button);
|
||||
game.stage.add(panel);
|
||||
// 使用插件
|
||||
engine.use(MyPlugin);
|
||||
```
|
||||
|
||||
### 自定义元素
|
||||
|
||||
可以通过继承 `BaseElement` 创建自定义元素:
|
||||
|
||||
```javascript
|
||||
import BaseElement from './src/elements/BaseElement.js';
|
||||
|
||||
class CustomElement extends BaseElement {
|
||||
constructor(x, y, width, height, engineId) {
|
||||
super('div', engineId);
|
||||
this.setPosition(x, y);
|
||||
this.setSize(width, height);
|
||||
// 添加自定义逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 游戏对象和组件
|
||||
|
||||
可以通过GameObject和Component系统创建复杂的游戏对象:
|
||||
|
||||
```javascript
|
||||
import { GameObject } from './src/elements/GameObject.js';
|
||||
import { PhysicsComponent, ColliderComponent } from './src/elements/Component.js';
|
||||
|
||||
class Player extends GameObject {
|
||||
constructor(x, y) {
|
||||
super(x, y, 50, 50);
|
||||
// 添加物理组件
|
||||
this.addComponent('physics', new PhysicsComponent({
|
||||
velocityX: 0,
|
||||
velocityY: 0,
|
||||
friction: 0.9
|
||||
}));
|
||||
|
||||
// 添加碰撞组件
|
||||
this.addComponent('collider', new ColliderComponent({
|
||||
width: 50,
|
||||
height: 50
|
||||
}));
|
||||
}
|
||||
|
||||
update(deltaTime) {
|
||||
super.update(deltaTime);
|
||||
// 自定义更新逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 示例游戏
|
||||
|
||||
项目包含一个完整的太空射击游戏示例,展示了引擎的各种功能:
|
||||
|
||||
1. 游戏对象系统
|
||||
2. 组件系统
|
||||
3. 碰撞检测
|
||||
4. 动画系统
|
||||
5. 音频管理
|
||||
6. 场景管理
|
||||
7. UI系统
|
||||
8. 摄像机系统
|
||||
9. 粒子效果
|
||||
10. 场景过渡效果
|
||||
|
||||
要运行示例游戏,请在浏览器中打开 `examples/spaceShooter.html`。
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 所有元素位置基于舞台左上角(0,0)计算
|
||||
2. 使用 `Destroy()` 方法会完全移除舞台并清理内存
|
||||
2. 使用 `destroy()` 方法会完全移除舞台并清理内存
|
||||
3. 图像元素自动添加 `user-drag: none` 防止拖动
|
||||
4. 舞台默认启用硬件加速 (`transform: translateZ(0)`)
|
||||
5. 每个引擎实例有唯一ID标识 (`data-engine-id`)
|
||||
6. 游戏循环基于requestAnimationFrame实现
|
||||
7. 坐标系统基于世界坐标和屏幕坐标的转换
|
||||
|
||||
这个轻量级引擎适合创建简单的 2D 界面和游戏原型,使用原生 DOM 操作,无需额外依赖。
|
||||
Pandona Engine是一个功能完整的2D游戏引擎,适合创建各种类型的2D游戏和动画,使用原生DOM操作,无需额外依赖。
|
||||
26
check_example.js
Normal file
26
check_example.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { readdir, stat } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
|
||||
async function listDirectory(path, indent = 0) {
|
||||
try {
|
||||
const items = await readdir(path);
|
||||
for (const item of items) {
|
||||
const itemPath = join(path, item);
|
||||
const stats = await stat(itemPath);
|
||||
const prefix = ' '.repeat(indent);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
console.log(`${prefix}[DIR] ${item}`);
|
||||
await listDirectory(itemPath, indent + 1);
|
||||
} else {
|
||||
console.log(`${prefix}[FILE] ${item}`);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error reading directory ${path}:`, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 显示项目中的example目录结构
|
||||
console.log('项目中的example目录结构:');
|
||||
await listDirectory('J:\\git\\cssEngine\\template-example');
|
||||
26
debug.js
Normal file
26
debug.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import PE from './src/index.js';
|
||||
|
||||
// 创建引擎实例
|
||||
const engine = PE.create();
|
||||
|
||||
// 等待一段时间让场景加载
|
||||
setTimeout(() => {
|
||||
console.log('Engine:', engine);
|
||||
console.log('Current scene:', engine.currentScene);
|
||||
console.log('Stage:', engine.stage);
|
||||
|
||||
// 检查场景容器中的元素
|
||||
if (engine.currentScene) {
|
||||
console.log('Scene container:', engine.currentScene.container);
|
||||
console.log('Scene elements:', engine.currentScene.elements);
|
||||
console.log('Scene container children:', engine.currentScene.container.children.length);
|
||||
|
||||
// 遍历所有子元素
|
||||
for (let i = 0; i < engine.currentScene.container.children.length; i++) {
|
||||
const child = engine.currentScene.container.children[i];
|
||||
console.log('Child element:', i, child.tagName, child.className, child.style.cssText);
|
||||
}
|
||||
} else {
|
||||
console.log('No current scene loaded');
|
||||
}
|
||||
}, 2000);
|
||||
1
dist-template/assets/index-1973dde7.css
Normal file
1
dist-template/assets/index-1973dde7.css
Normal file
@@ -0,0 +1 @@
|
||||
*{background:white}
|
||||
91
dist-template/assets/index-6271e228.js
Normal file
91
dist-template/assets/index-6271e228.js
Normal file
File diff suppressed because one or more lines are too long
91
dist-template/assets/index-880f7c5b.js
Normal file
91
dist-template/assets/index-880f7c5b.js
Normal file
File diff suppressed because one or more lines are too long
91
dist-template/assets/index-a09a4142.js
Normal file
91
dist-template/assets/index-a09a4142.js
Normal file
File diff suppressed because one or more lines are too long
91
dist-template/assets/index-aa617c3d.js
Normal file
91
dist-template/assets/index-aa617c3d.js
Normal file
File diff suppressed because one or more lines are too long
90
dist-template/assets/index-dab6cb02.js
Normal file
90
dist-template/assets/index-dab6cb02.js
Normal file
File diff suppressed because one or more lines are too long
1
dist-template/assets/index-e4e95c79.css
Normal file
1
dist-template/assets/index-e4e95c79.css
Normal file
@@ -0,0 +1 @@
|
||||
*{background:white}.test-sprite{width:100px;height:100px;background-color:#ff5722;border-radius:50%;cursor:pointer;position:absolute;top:50px;left:50px;border:2px solid #e64a19}.test-box{width:200px;height:50px;background-color:#2196f3;color:#fff;display:flex;align-items:center;justify-content:center;position:absolute;top:200px;left:50px;border:2px solid #1976d2;border-radius:4px;cursor:pointer}.test-text{position:absolute;top:300px;left:50px;color:#333;font-size:20px;font-weight:700}.menu-item{width:150px;height:40px;background-color:#9c27b0;color:#fff;display:flex;align-items:center;justify-content:center;position:absolute;left:50px;border:2px solid #7b1fa2;border-radius:4px;cursor:pointer;font-family:Arial,sans-serif;font-size:16px}
|
||||
89
dist-template/assets/index-e4ee4c1a.js
Normal file
89
dist-template/assets/index-e4ee4c1a.js
Normal file
File diff suppressed because one or more lines are too long
91
dist-template/assets/index-f8561862.js
Normal file
91
dist-template/assets/index-f8561862.js
Normal file
File diff suppressed because one or more lines are too long
1
dist-template/assets/sences-2e06be56.js
Normal file
1
dist-template/assets/sences-2e06be56.js
Normal file
@@ -0,0 +1 @@
|
||||
const e=[{path:"/sence1",title:"主场景"},{path:"/sence2",title:"测试场景"}],t="PC",s={sence:e,platform:t};export{s as default,t as platform,e as sence};
|
||||
15
fetch-page.js
Normal file
15
fetch-page.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import http from 'http';
|
||||
|
||||
http.get('http://localhost:3003/', (res) => {
|
||||
let data = '';
|
||||
|
||||
res.on('data', (chunk) => {
|
||||
data += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
console.log(data.substring(0, 500));
|
||||
});
|
||||
}).on('error', (err) => {
|
||||
console.log('Error: ' + err.message);
|
||||
});
|
||||
21
guide/README.md
Normal file
21
guide/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# PE引擎使用指南
|
||||
|
||||
欢迎使用PE引擎!本指南将帮助你了解和使用PE引擎的所有功能。
|
||||
|
||||
## 目录
|
||||
|
||||
- [简介](./introduction.md)
|
||||
- [快速上手](./quick-start.md)
|
||||
- [基础教程](./essentials/)
|
||||
- [创建应用实例](./essentials/application.md)
|
||||
- [元素系统](./essentials/elements.md)
|
||||
- [场景系统](./essentials/scenes.md)
|
||||
- [样式处理](./essentials/styling.md)
|
||||
- [事件处理](./essentials/event-handling.md)
|
||||
- [生命周期](./essentials/lifecycle.md)
|
||||
- [组件](./components/)
|
||||
- [组件基础](./components/README.md)
|
||||
- [进阶主题](./advanced/)
|
||||
- [进阶概念](./advanced/README.md)
|
||||
- [API参考](./api/)
|
||||
- [API文档](./api/README.md)
|
||||
455
guide/advanced/README.md
Normal file
455
guide/advanced/README.md
Normal file
@@ -0,0 +1,455 @@
|
||||
# 进阶主题
|
||||
|
||||
在掌握了PE引擎的基础知识后,我们可以探索一些更高级的功能和概念。这些进阶主题将帮助你构建更复杂、更高效的应用。
|
||||
|
||||
## 目录
|
||||
|
||||
- [动画系统](./animation)
|
||||
- [状态管理](./state-management)
|
||||
- [插件系统](./plugins)
|
||||
- [性能优化](./performance)
|
||||
- [测试](./testing)
|
||||
- [部署](./deployment)
|
||||
|
||||
## 动画系统
|
||||
|
||||
PE引擎内置了强大的动画系统,支持补间动画、帧动画和序列动画。
|
||||
|
||||
### 补间动画
|
||||
|
||||
补间动画允许你在两个状态之间创建平滑的过渡:
|
||||
|
||||
```javascript
|
||||
// 创建补间动画
|
||||
const tween = game.tween(element.element)
|
||||
.to({
|
||||
left: '500px',
|
||||
top: '300px',
|
||||
opacity: 0.5
|
||||
}, 2000) // 持续2秒
|
||||
.easing('easeInOutQuad') // 缓动函数
|
||||
.onUpdate(() => {
|
||||
console.log('动画更新')
|
||||
})
|
||||
.onComplete(() => {
|
||||
console.log('动画完成')
|
||||
})
|
||||
.start()
|
||||
```
|
||||
|
||||
### 帧动画
|
||||
|
||||
帧动画通过连续播放一系列图像来创建动画效果:
|
||||
|
||||
```javascript
|
||||
// 创建帧动画
|
||||
game.createFrameAnimation('walk', [
|
||||
'img/walk1.png',
|
||||
'img/walk2.png',
|
||||
'img/walk3.png',
|
||||
'img/walk4.png'
|
||||
], 10) // 10帧每秒
|
||||
|
||||
// 播放帧动画
|
||||
game.playFrameAnimation(sprite, 'walk', true) // 循环播放
|
||||
```
|
||||
|
||||
### 序列动画
|
||||
|
||||
序列动画允许你按顺序播放多个动画:
|
||||
|
||||
```javascript
|
||||
// 创建动画序列
|
||||
game.createSequence('moveAndFade', [
|
||||
{
|
||||
target: element.element,
|
||||
props: { left: '500px' },
|
||||
duration: 1000
|
||||
},
|
||||
{
|
||||
target: element.element,
|
||||
props: { opacity: 0 },
|
||||
duration: 500
|
||||
}
|
||||
])
|
||||
|
||||
// 播放序列动画
|
||||
game.playSequence('moveAndFade')
|
||||
```
|
||||
|
||||
## 状态管理
|
||||
|
||||
对于复杂应用,合理的状态管理至关重要。PE引擎提供了灵活的状态管理方案。
|
||||
|
||||
### 全局状态
|
||||
|
||||
```javascript
|
||||
// 创建全局状态管理器
|
||||
class StateManager {
|
||||
constructor() {
|
||||
this.state = {}
|
||||
this.listeners = {}
|
||||
}
|
||||
|
||||
// 设置状态
|
||||
setState(key, value) {
|
||||
this.state[key] = value
|
||||
this.notifyListeners(key, value)
|
||||
}
|
||||
|
||||
// 获取状态
|
||||
getState(key) {
|
||||
return this.state[key]
|
||||
}
|
||||
|
||||
// 订阅状态变化
|
||||
subscribe(key, callback) {
|
||||
if (!this.listeners[key]) {
|
||||
this.listeners[key] = []
|
||||
}
|
||||
this.listeners[key].push(callback)
|
||||
}
|
||||
|
||||
// 通知监听器
|
||||
notifyListeners(key, value) {
|
||||
if (this.listeners[key]) {
|
||||
this.listeners[key].forEach(callback => callback(value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局状态管理器实例
|
||||
const stateManager = new StateManager()
|
||||
|
||||
// 在组件中使用
|
||||
stateManager.setState('user', { name: '张三', age: 25 })
|
||||
stateManager.subscribe('user', (user) => {
|
||||
console.log('用户信息更新:', user)
|
||||
})
|
||||
```
|
||||
|
||||
### 场景状态
|
||||
|
||||
每个场景也可以有自己的状态管理:
|
||||
|
||||
```html
|
||||
<script>
|
||||
// 场景内部状态
|
||||
let sceneState = {
|
||||
data: [],
|
||||
loading: false,
|
||||
error: null
|
||||
}
|
||||
|
||||
// 更新场景状态
|
||||
function updateState(newState) {
|
||||
sceneState = { ...sceneState, ...newState }
|
||||
updateUI()
|
||||
}
|
||||
|
||||
// 异步数据加载
|
||||
async function loadData() {
|
||||
updateState({ loading: true })
|
||||
|
||||
try {
|
||||
const data = await fetchData()
|
||||
updateState({ data, loading: false })
|
||||
} catch (error) {
|
||||
updateState({ error: error.message, loading: false })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 插件系统
|
||||
|
||||
PE引擎支持插件系统,允许你扩展引擎的功能。
|
||||
|
||||
### 创建插件
|
||||
|
||||
```javascript
|
||||
// 定义插件
|
||||
const LoggerPlugin = {
|
||||
name: 'LoggerPlugin',
|
||||
install(engine, options) {
|
||||
console.log('LoggerPlugin installed with options:', options)
|
||||
|
||||
// 扩展引擎功能
|
||||
engine.log = function(message) {
|
||||
console.log(`[PE Logger]: ${message}`)
|
||||
}
|
||||
|
||||
// 监听引擎事件
|
||||
engine.eventBus.on('sceneChanged', (data) => {
|
||||
this.log(`Scene changed to: ${data.path}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 使用插件
|
||||
game.use(LoggerPlugin, { level: 'debug' })
|
||||
```
|
||||
|
||||
### 内置插件
|
||||
|
||||
PE引擎提供了一些有用的内置插件:
|
||||
|
||||
```javascript
|
||||
// 路由插件
|
||||
import { RouterPlugin } from 'pe-engine/plugins'
|
||||
|
||||
game.use(RouterPlugin, {
|
||||
mode: 'history', // 或 'hash'
|
||||
routes: [
|
||||
{ path: '/', component: 'Home' },
|
||||
{ path: '/about', component: 'About' }
|
||||
]
|
||||
})
|
||||
|
||||
// 状态管理插件
|
||||
import { StatePlugin } from 'pe-engine/plugins'
|
||||
|
||||
game.use(StatePlugin, {
|
||||
initialState: {
|
||||
user: null,
|
||||
theme: 'light'
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 性能优化
|
||||
|
||||
构建高性能的PE应用需要注意以下几个方面:
|
||||
|
||||
### 1. 虚拟化列表
|
||||
|
||||
对于大量数据的列表渲染,使用虚拟化技术:
|
||||
|
||||
```javascript
|
||||
// 虚拟化列表组件
|
||||
class VirtualList {
|
||||
constructor(container, items, itemHeight) {
|
||||
this.container = container
|
||||
this.items = items
|
||||
this.itemHeight = itemHeight
|
||||
this.visibleCount = Math.ceil(container.clientHeight / itemHeight) + 2
|
||||
this.startIndex = 0
|
||||
|
||||
this.render()
|
||||
this.bindEvents()
|
||||
}
|
||||
|
||||
render() {
|
||||
const fragment = document.createDocumentFragment()
|
||||
const endIndex = Math.min(this.startIndex + this.visibleCount, this.items.length)
|
||||
|
||||
for (let i = this.startIndex; i < endIndex; i++) {
|
||||
const itemElement = this.createItemElement(this.items[i], i)
|
||||
itemElement.style.transform = `translateY(${i * this.itemHeight}px)`
|
||||
fragment.appendChild(itemElement)
|
||||
}
|
||||
|
||||
this.container.innerHTML = ''
|
||||
this.container.appendChild(fragment)
|
||||
}
|
||||
|
||||
createItemElement(item, index) {
|
||||
const element = document.createElement('div')
|
||||
element.className = 'list-item'
|
||||
element.textContent = item.text
|
||||
element.style.height = `${this.itemHeight}px`
|
||||
element.style.position = 'absolute'
|
||||
element.style.width = '100%'
|
||||
return element
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.container.addEventListener('scroll', () => {
|
||||
const newStartIndex = Math.floor(this.container.scrollTop / this.itemHeight)
|
||||
if (newStartIndex !== this.startIndex) {
|
||||
this.startIndex = newStartIndex
|
||||
this.render()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 防抖和节流
|
||||
|
||||
对于频繁触发的操作,使用防抖和节流:
|
||||
|
||||
```javascript
|
||||
// 防抖函数
|
||||
function debounce(func, wait) {
|
||||
let timeout
|
||||
return function(...args) {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => func.apply(this, args), wait)
|
||||
}
|
||||
}
|
||||
|
||||
// 节流函数
|
||||
function throttle(func, limit) {
|
||||
let inThrottle
|
||||
return function(...args) {
|
||||
if (!inThrottle) {
|
||||
func.apply(this, args)
|
||||
inThrottle = true
|
||||
setTimeout(() => inThrottle = false, limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
const handleResize = debounce(() => {
|
||||
console.log('窗口大小改变')
|
||||
}, 300)
|
||||
|
||||
const handleScroll = throttle(() => {
|
||||
console.log('页面滚动')
|
||||
}, 100)
|
||||
|
||||
window.addEventListener('resize', handleResize)
|
||||
window.addEventListener('scroll', handleScroll)
|
||||
```
|
||||
|
||||
### 3. 懒加载
|
||||
|
||||
对于图片和组件,使用懒加载技术:
|
||||
|
||||
```javascript
|
||||
// 图片懒加载
|
||||
class ImageLazyLoader {
|
||||
constructor() {
|
||||
this.images = []
|
||||
this.observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
this.loadImage(entry.target)
|
||||
this.observer.unobserve(entry.target)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
loadImage(img) {
|
||||
const src = img.dataset.src
|
||||
if (src) {
|
||||
img.src = src
|
||||
img.classList.remove('lazy')
|
||||
img.classList.add('loaded')
|
||||
}
|
||||
}
|
||||
|
||||
observe(img) {
|
||||
this.observer.observe(img)
|
||||
}
|
||||
}
|
||||
|
||||
// 使用懒加载
|
||||
const lazyLoader = new ImageLazyLoader()
|
||||
document.querySelectorAll('img[data-src]').forEach(img => {
|
||||
lazyLoader.observe(img)
|
||||
})
|
||||
```
|
||||
|
||||
## 测试
|
||||
|
||||
编写测试是确保应用质量的重要环节。
|
||||
|
||||
### 单元测试
|
||||
|
||||
使用Jest等测试框架编写单元测试:
|
||||
|
||||
```javascript
|
||||
// 测试元素创建功能
|
||||
describe('Element Creation', () => {
|
||||
test('should create sprite element', () => {
|
||||
const sprite = game.create('sprite', { x: 100, y: 100 })
|
||||
expect(sprite).toBeDefined()
|
||||
expect(sprite.getX()).toBe(100)
|
||||
expect(sprite.getY()).toBe(100)
|
||||
})
|
||||
|
||||
test('should create box element', () => {
|
||||
const box = game.create('box', { width: 200, height: 100 })
|
||||
expect(box.getWidth()).toBe(200)
|
||||
expect(box.getHeight()).toBe(100)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### 集成测试
|
||||
|
||||
测试组件和场景的集成:
|
||||
|
||||
```javascript
|
||||
// 测试场景切换
|
||||
describe('Scene Navigation', () => {
|
||||
test('should navigate to about page', async () => {
|
||||
// 模拟场景切换
|
||||
await game.switchToPath('/about')
|
||||
|
||||
// 验证场景是否正确加载
|
||||
const currentScene = game.getCurrentScene()
|
||||
expect(currentScene.path).toBe('/about')
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## 部署
|
||||
|
||||
将PE应用部署到生产环境需要注意以下几点:
|
||||
|
||||
### 构建优化
|
||||
|
||||
```javascript
|
||||
// vite.config.js
|
||||
import { defineConfig } from 'vite'
|
||||
import { resolve } from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
build: {
|
||||
// 代码分割
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: ['pe-engine'],
|
||||
utils: ['./src/utils'],
|
||||
}
|
||||
}
|
||||
},
|
||||
// 压缩
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
drop_debugger: true
|
||||
}
|
||||
}
|
||||
},
|
||||
// 静态资源处理
|
||||
assetsInclude: ['**/*.pe', '**/*.less']
|
||||
})
|
||||
```
|
||||
|
||||
### 环境配置
|
||||
|
||||
```javascript
|
||||
// 配置不同环境
|
||||
const config = {
|
||||
development: {
|
||||
apiBaseUrl: 'http://localhost:3000',
|
||||
debug: true
|
||||
},
|
||||
production: {
|
||||
apiBaseUrl: 'https://api.example.com',
|
||||
debug: false
|
||||
}
|
||||
}
|
||||
|
||||
const currentConfig = config[process.env.NODE_ENV || 'development']
|
||||
```
|
||||
|
||||
通过以上进阶主题的学习,你将能够构建更复杂、更高效的PE应用。在接下来的章节中,我们将深入探讨每个主题的更多细节。
|
||||
600
guide/api/README.md
Normal file
600
guide/api/README.md
Normal file
@@ -0,0 +1,600 @@
|
||||
# API参考
|
||||
|
||||
本章节提供了PE引擎所有公共API的详细参考文档。
|
||||
|
||||
## 全局API
|
||||
|
||||
### PE
|
||||
|
||||
PE是引擎的主要入口点。
|
||||
|
||||
#### PE.create(options)
|
||||
|
||||
创建一个新的PE引擎实例。
|
||||
|
||||
```javascript
|
||||
import PE from 'pe-engine'
|
||||
|
||||
const game = PE.create({
|
||||
width: 800,
|
||||
height: 600,
|
||||
background: '#f0f0f0',
|
||||
fps: 60
|
||||
})
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
| 参数 | 类型 | 默认值 | 描述 |
|
||||
|------|------|--------|------|
|
||||
| options | Object | {} | 配置选项 |
|
||||
| options.width | number | 800 | 舞台宽度 |
|
||||
| options.height | number | 600 | 舞台高度 |
|
||||
| options.background | string | '#f0f0f0' | 背景色 |
|
||||
| options.fps | number | 60 | 帧率 |
|
||||
|
||||
**返回值:**
|
||||
|
||||
Engine实例
|
||||
|
||||
#### PE.navigateTo(path)
|
||||
|
||||
导航到指定路径的场景。
|
||||
|
||||
```javascript
|
||||
PE.navigateTo('/about')
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|------|------|------|
|
||||
| path | string | 目标场景路径 |
|
||||
|
||||
#### PE.version
|
||||
|
||||
获取PE引擎版本。
|
||||
|
||||
```javascript
|
||||
console.log(PE.version) // '1.0.0'
|
||||
```
|
||||
|
||||
### 生命周期钩子
|
||||
|
||||
#### onLoad(callback)
|
||||
|
||||
场景加载时调用的钩子。
|
||||
|
||||
```javascript
|
||||
onLoad(() => {
|
||||
console.log('场景加载完成')
|
||||
})
|
||||
```
|
||||
|
||||
#### onShow(callback)
|
||||
|
||||
场景显示时调用的钩子。
|
||||
|
||||
```javascript
|
||||
onShow(() => {
|
||||
console.log('场景显示')
|
||||
})
|
||||
```
|
||||
|
||||
#### onHide(callback)
|
||||
|
||||
场景隐藏时调用的钩子。
|
||||
|
||||
```javascript
|
||||
onHide(() => {
|
||||
console.log('场景隐藏')
|
||||
})
|
||||
```
|
||||
|
||||
#### onDestory(callback)
|
||||
|
||||
场景销毁时调用的钩子。
|
||||
|
||||
```javascript
|
||||
onDestory(() => {
|
||||
console.log('场景销毁')
|
||||
})
|
||||
```
|
||||
|
||||
## Engine实例API
|
||||
|
||||
### 元素创建
|
||||
|
||||
#### create(type, options)
|
||||
|
||||
创建元素。
|
||||
|
||||
```javascript
|
||||
const sprite = game.create('sprite', { x: 100, y: 100 })
|
||||
const box = game.create('box', { x: 200, y: 200, width: 100, height: 50 })
|
||||
```
|
||||
|
||||
**参数:**
|
||||
|
||||
| 参数 | 类型 | 描述 |
|
||||
|------|------|------|
|
||||
| type | string | 元素类型 ('sprite', 'box', 'text', 'html', 'svg') |
|
||||
| options | Object | 元素配置选项 |
|
||||
|
||||
**返回值:**
|
||||
|
||||
创建的元素实例
|
||||
|
||||
#### createSprite(image, x, y, width, height)
|
||||
|
||||
创建精灵元素。
|
||||
|
||||
```javascript
|
||||
const sprite = game.createSprite('path/to/image.png', 100, 100, 50, 50)
|
||||
```
|
||||
|
||||
#### createBox(x, y, width, height)
|
||||
|
||||
创建盒子元素。
|
||||
|
||||
```javascript
|
||||
const box = game.createBox(100, 100, 200, 100)
|
||||
```
|
||||
|
||||
#### createText(text, x, y)
|
||||
|
||||
创建文本元素。
|
||||
|
||||
```javascript
|
||||
const text = game.createText('Hello PE!', 100, 100)
|
||||
```
|
||||
|
||||
#### createHtml(html, x, y)
|
||||
|
||||
创建HTML元素。
|
||||
|
||||
```javascript
|
||||
const htmlElement = game.createHtml('<div>HTML内容</div>', 100, 100)
|
||||
```
|
||||
|
||||
#### createSvg(x, y, width, height, content)
|
||||
|
||||
创建SVG元素。
|
||||
|
||||
```javascript
|
||||
const svgElement = game.createSvg(100, 100, 200, 200, '<circle cx="100" cy="100" r="50" />')
|
||||
```
|
||||
|
||||
### 场景管理
|
||||
|
||||
#### switchToPath(path)
|
||||
|
||||
切换到指定路径的场景。
|
||||
|
||||
```javascript
|
||||
await game.switchToPath('/about')
|
||||
```
|
||||
|
||||
#### preloadScenes(paths)
|
||||
|
||||
预加载场景。
|
||||
|
||||
```javascript
|
||||
await game.preloadScenes(['/home', '/about', '/contact'])
|
||||
```
|
||||
|
||||
#### getCurrentPath()
|
||||
|
||||
获取当前场景路径。
|
||||
|
||||
```javascript
|
||||
const currentPath = game.getCurrentPath()
|
||||
```
|
||||
|
||||
#### getCurrentScene()
|
||||
|
||||
获取当前场景对象。
|
||||
|
||||
```javascript
|
||||
const currentScene = game.getCurrentScene()
|
||||
```
|
||||
|
||||
#### getSceneElement(name)
|
||||
|
||||
获取场景中的元素。
|
||||
|
||||
```javascript
|
||||
const element = game.getSceneElement('my-button')
|
||||
```
|
||||
|
||||
### 动画系统
|
||||
|
||||
#### tween(target, duration, easing)
|
||||
|
||||
创建补间动画。
|
||||
|
||||
```javascript
|
||||
const tween = game.tween(element.element, 1000, 'easeInOutQuad')
|
||||
.to({ left: '500px' })
|
||||
.start()
|
||||
```
|
||||
|
||||
#### createFrameAnimation(name, frames, frameRate)
|
||||
|
||||
创建帧动画。
|
||||
|
||||
```javascript
|
||||
game.createFrameAnimation('walk', [
|
||||
'img/walk1.png',
|
||||
'img/walk2.png',
|
||||
'img/walk3.png'
|
||||
], 10)
|
||||
```
|
||||
|
||||
#### playFrameAnimation(sprite, animationName, loop)
|
||||
|
||||
播放帧动画。
|
||||
|
||||
```javascript
|
||||
game.playFrameAnimation(sprite, 'walk', true)
|
||||
```
|
||||
|
||||
#### createSequence(name, animations)
|
||||
|
||||
创建动画序列。
|
||||
|
||||
```javascript
|
||||
game.createSequence('moveAndFade', [
|
||||
{ target: element.element, props: { left: '500px' }, duration: 1000 },
|
||||
{ target: element.element, props: { opacity: 0 }, duration: 500 }
|
||||
])
|
||||
```
|
||||
|
||||
#### playSequence(sequenceName, loop)
|
||||
|
||||
播放动画序列。
|
||||
|
||||
```javascript
|
||||
game.playSequence('moveAndFade')
|
||||
```
|
||||
|
||||
### 资源管理
|
||||
|
||||
#### load(src)
|
||||
|
||||
加载资源。
|
||||
|
||||
```javascript
|
||||
const image = await game.load('path/to/image.png')
|
||||
```
|
||||
|
||||
#### loadSound(name, src, options)
|
||||
|
||||
加载音效。
|
||||
|
||||
```javascript
|
||||
game.loadSound('jump', 'path/to/jump.mp3')
|
||||
```
|
||||
|
||||
#### loadMusic(name, src, options)
|
||||
|
||||
加载音乐。
|
||||
|
||||
```javascript
|
||||
game.loadMusic('bgm', 'path/to/background.mp3')
|
||||
```
|
||||
|
||||
#### playSound(name, options)
|
||||
|
||||
播放音效。
|
||||
|
||||
```javascript
|
||||
game.playSound('jump')
|
||||
```
|
||||
|
||||
#### playMusic(name, options)
|
||||
|
||||
播放音乐。
|
||||
|
||||
```javascript
|
||||
game.playMusic('bgm')
|
||||
```
|
||||
|
||||
### 摄像机控制
|
||||
|
||||
#### setCameraPosition(x, y)
|
||||
|
||||
设置摄像机位置。
|
||||
|
||||
```javascript
|
||||
game.setCameraPosition(100, 100)
|
||||
```
|
||||
|
||||
#### moveCamera(x, y)
|
||||
|
||||
移动摄像机。
|
||||
|
||||
```javascript
|
||||
game.moveCamera(50, 50)
|
||||
```
|
||||
|
||||
#### setCameraZoom(zoom)
|
||||
|
||||
设置摄像机缩放。
|
||||
|
||||
```javascript
|
||||
game.setCameraZoom(1.5)
|
||||
```
|
||||
|
||||
#### follow(target, offset)
|
||||
|
||||
跟随目标。
|
||||
|
||||
```javascript
|
||||
game.follow(playerSprite, { x: 0, y: -50 })
|
||||
```
|
||||
|
||||
#### shakeCamera(intensity, duration)
|
||||
|
||||
摄像机震动效果。
|
||||
|
||||
```javascript
|
||||
game.shakeCamera(10, 500)
|
||||
```
|
||||
|
||||
### 事件系统
|
||||
|
||||
#### eventBus
|
||||
|
||||
获取事件总线实例。
|
||||
|
||||
```javascript
|
||||
// 发送事件
|
||||
game.eventBus.emit('custom-event', { data: 'example' })
|
||||
|
||||
// 监听事件
|
||||
game.eventBus.on('custom-event', (data) => {
|
||||
console.log('接收到事件:', data)
|
||||
})
|
||||
```
|
||||
|
||||
### 定时器
|
||||
|
||||
#### setTimeout(callback, delay)
|
||||
|
||||
设置定时器。
|
||||
|
||||
```javascript
|
||||
const timer = game.setTimeout(() => {
|
||||
console.log('定时器触发')
|
||||
}, 1000)
|
||||
```
|
||||
|
||||
#### clearTimeout(timer)
|
||||
|
||||
清除定时器。
|
||||
|
||||
```javascript
|
||||
game.clearTimeout(timer)
|
||||
```
|
||||
|
||||
#### setInterval(callback, interval)
|
||||
|
||||
设置间隔执行。
|
||||
|
||||
```javascript
|
||||
const intervalId = game.setInterval(() => {
|
||||
console.log('间隔执行')
|
||||
}, 1000)
|
||||
```
|
||||
|
||||
#### clearInterval(intervalId)
|
||||
|
||||
清除间隔执行。
|
||||
|
||||
```javascript
|
||||
game.clearInterval(intervalId)
|
||||
```
|
||||
|
||||
## 元素API
|
||||
|
||||
所有PE元素都具有以下通用API:
|
||||
|
||||
### 位置和尺寸
|
||||
|
||||
#### setPosition(x, y)
|
||||
|
||||
设置元素位置。
|
||||
|
||||
```javascript
|
||||
element.setPosition(100, 200)
|
||||
```
|
||||
|
||||
#### setSize(width, height)
|
||||
|
||||
设置元素尺寸。
|
||||
|
||||
```javascript
|
||||
element.setSize(300, 150)
|
||||
```
|
||||
|
||||
#### getX()
|
||||
|
||||
获取元素X坐标。
|
||||
|
||||
```javascript
|
||||
const x = element.getX()
|
||||
```
|
||||
|
||||
#### getY()
|
||||
|
||||
获取元素Y坐标。
|
||||
|
||||
```javascript
|
||||
const y = element.getY()
|
||||
```
|
||||
|
||||
#### getWidth()
|
||||
|
||||
获取元素宽度。
|
||||
|
||||
```javascript
|
||||
const width = element.getWidth()
|
||||
```
|
||||
|
||||
#### getHeight()
|
||||
|
||||
获取元素高度。
|
||||
|
||||
```javascript
|
||||
const height = element.getHeight()
|
||||
```
|
||||
|
||||
### 样式操作
|
||||
|
||||
#### setStyle(property, value)
|
||||
|
||||
设置单个样式属性。
|
||||
|
||||
```javascript
|
||||
element.setStyle('backgroundColor', '#3498db')
|
||||
```
|
||||
|
||||
#### setStyles(styles)
|
||||
|
||||
设置多个样式属性。
|
||||
|
||||
```javascript
|
||||
element.setStyles({
|
||||
backgroundColor: '#3498db',
|
||||
borderRadius: '8px'
|
||||
})
|
||||
```
|
||||
|
||||
#### addClass(className)
|
||||
|
||||
添加CSS类。
|
||||
|
||||
```javascript
|
||||
element.addClass('my-class')
|
||||
```
|
||||
|
||||
#### removeClass(className)
|
||||
|
||||
移除CSS类。
|
||||
|
||||
```javascript
|
||||
element.removeClass('my-class')
|
||||
```
|
||||
|
||||
#### hasClass(className)
|
||||
|
||||
检查是否包含CSS类。
|
||||
|
||||
```javascript
|
||||
if (element.hasClass('my-class')) {
|
||||
// 执行相应操作
|
||||
}
|
||||
```
|
||||
|
||||
### 显示控制
|
||||
|
||||
#### show()
|
||||
|
||||
显示元素。
|
||||
|
||||
```javascript
|
||||
element.show()
|
||||
```
|
||||
|
||||
#### hide()
|
||||
|
||||
隐藏元素。
|
||||
|
||||
```javascript
|
||||
element.hide()
|
||||
```
|
||||
|
||||
#### toggle()
|
||||
|
||||
切换显示状态。
|
||||
|
||||
```javascript
|
||||
element.toggle()
|
||||
```
|
||||
|
||||
### 文本元素特有API
|
||||
|
||||
#### setText(text)
|
||||
|
||||
设置文本内容。
|
||||
|
||||
```javascript
|
||||
textElement.setText('新的文本内容')
|
||||
```
|
||||
|
||||
### HTML元素特有API
|
||||
|
||||
#### setHtml(html)
|
||||
|
||||
设置HTML内容。
|
||||
|
||||
```javascript
|
||||
htmlElement.setHtml('<div>新的HTML内容</div>')
|
||||
```
|
||||
|
||||
## 插件API
|
||||
|
||||
### use(plugin, options)
|
||||
|
||||
安装插件。
|
||||
|
||||
```javascript
|
||||
game.use(MyPlugin, { option1: 'value1' })
|
||||
```
|
||||
|
||||
## 配置选项
|
||||
|
||||
### 引擎配置
|
||||
|
||||
```javascript
|
||||
const game = PE.create({
|
||||
// 舞台尺寸
|
||||
width: 800,
|
||||
height: 600,
|
||||
|
||||
// 背景色
|
||||
background: '#f0f0f0',
|
||||
|
||||
// 帧率
|
||||
fps: 60
|
||||
})
|
||||
```
|
||||
|
||||
### 资源加载配置
|
||||
|
||||
```javascript
|
||||
game.loadSound('jump', 'path/to/jump.mp3', {
|
||||
volume: 0.5,
|
||||
loop: false
|
||||
})
|
||||
|
||||
game.loadMusic('bgm', 'path/to/background.mp3', {
|
||||
volume: 0.8,
|
||||
loop: true
|
||||
})
|
||||
```
|
||||
|
||||
### 动画配置
|
||||
|
||||
```javascript
|
||||
const tween = game.tween(element.element, 1000, 'easeInOutQuad')
|
||||
.to({ left: '500px' }, 1000)
|
||||
.delay(500) // 延迟500ms
|
||||
.onStart(() => console.log('动画开始'))
|
||||
.onUpdate(() => console.log('动画更新'))
|
||||
.onComplete(() => console.log('动画完成'))
|
||||
.start()
|
||||
```
|
||||
|
||||
通过以上API参考,你可以详细了解PE引擎提供的所有功能和使用方法。在实际开发中,建议结合示例代码和文档说明来更好地理解和使用这些API。
|
||||
715
guide/components/README.md
Normal file
715
guide/components/README.md
Normal file
@@ -0,0 +1,715 @@
|
||||
# 组件
|
||||
|
||||
组件是PE引擎中可复用的UI构建块,它们将模板、样式和逻辑封装在一起,使得代码更加模块化和可维护。
|
||||
|
||||
## 什么是组件?
|
||||
|
||||
组件是PE应用中独立的、可复用的代码单元,它包含:
|
||||
|
||||
1. **模板** - 定义组件的结构和元素
|
||||
2. **样式** - 定义组件的外观和样式
|
||||
3. **逻辑** - 定义组件的行为和功能
|
||||
|
||||
## 创建组件
|
||||
|
||||
在PE中,组件可以通过创建独立的目录结构来定义:
|
||||
|
||||
```
|
||||
components/
|
||||
├── button/
|
||||
│ ├── index.pe
|
||||
│ └── index.less
|
||||
├── card/
|
||||
│ ├── index.pe
|
||||
│ └── index.less
|
||||
└── modal/
|
||||
├── index.pe
|
||||
└── index.less
|
||||
```
|
||||
|
||||
### 组件模板文件
|
||||
|
||||
组件模板文件与场景模板文件结构相同:
|
||||
|
||||
```html
|
||||
<!-- components/button/index.pe -->
|
||||
<sence>
|
||||
<box class="pe-button" @click="handleClick">
|
||||
<text class="button-text">{{ label }}</text>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 组件属性
|
||||
let label = '按钮'
|
||||
|
||||
// 组件事件
|
||||
let onClick = null
|
||||
|
||||
// 设置属性
|
||||
function setLabel(newLabel) {
|
||||
label = newLabel
|
||||
const textElement = game.getSceneElement('button-text')
|
||||
if (textElement) {
|
||||
textElement.element.textContent = label
|
||||
}
|
||||
}
|
||||
|
||||
// 设置事件处理器
|
||||
function setOnClick(handler) {
|
||||
onClick = handler
|
||||
}
|
||||
|
||||
// 事件处理函数
|
||||
function handleClick() {
|
||||
if (typeof onClick === 'function') {
|
||||
onClick()
|
||||
}
|
||||
}
|
||||
|
||||
// 组件初始化
|
||||
onLoad(() => {
|
||||
console.log('按钮组件加载')
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('按钮组件显示')
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### 组件样式文件
|
||||
|
||||
```less
|
||||
/* components/button/index.less */
|
||||
.pe-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 20px;
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.button-text {
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用组件
|
||||
|
||||
在场景中使用组件非常简单:
|
||||
|
||||
```html
|
||||
<!-- scenes/home/index.pe -->
|
||||
<sence>
|
||||
<!-- 使用按钮组件 -->
|
||||
<button @click="handleButtonClick"></button>
|
||||
|
||||
<!-- 带属性的组件 -->
|
||||
<button label="提交" @click="handleSubmit"></button>
|
||||
<button label="取消" @click="handleCancel"></button>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 导入组件
|
||||
import Button from '../../components/button/index.pe'
|
||||
|
||||
function handleButtonClick() {
|
||||
console.log('按钮被点击')
|
||||
}
|
||||
|
||||
function handleSubmit() {
|
||||
console.log('提交按钮被点击')
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
console.log('取消按钮被点击')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 组件通信
|
||||
|
||||
组件之间可以通过属性和事件进行通信。
|
||||
|
||||
### Props(属性)
|
||||
|
||||
父组件向子组件传递数据:
|
||||
|
||||
```html
|
||||
<!-- 父组件 -->
|
||||
<sence>
|
||||
<user-card
|
||||
name="张三"
|
||||
age="25"
|
||||
email="zhangsan@example.com"
|
||||
@edit="handleEditUser">
|
||||
</user-card>
|
||||
</sence>
|
||||
|
||||
<!-- 子组件 (components/user-card/index.pe) -->
|
||||
<sence>
|
||||
<box class="user-card">
|
||||
<text class="user-name">{{ name }}</text>
|
||||
<text class="user-age">年龄: {{ age }}</text>
|
||||
<text class="user-email">邮箱: {{ email }}</text>
|
||||
<box class="edit-button" @click="handleEdit">编辑</box>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 组件属性
|
||||
let name = ''
|
||||
let age = ''
|
||||
let email = ''
|
||||
|
||||
// 组件事件
|
||||
let onEdit = null
|
||||
|
||||
// 设置属性的方法
|
||||
function setName(value) {
|
||||
name = value
|
||||
}
|
||||
|
||||
function setAge(value) {
|
||||
age = value
|
||||
}
|
||||
|
||||
function setEmail(value) {
|
||||
email = value
|
||||
}
|
||||
|
||||
// 设置事件处理器
|
||||
function setOnEdit(handler) {
|
||||
onEdit = handler
|
||||
}
|
||||
|
||||
// 事件处理函数
|
||||
function handleEdit() {
|
||||
if (typeof onEdit === 'function') {
|
||||
onEdit({ name, age, email })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### Events(事件)
|
||||
|
||||
子组件向父组件传递数据:
|
||||
|
||||
```html
|
||||
<!-- 子组件触发事件 -->
|
||||
<script>
|
||||
function handleEdit() {
|
||||
// 触发自定义事件
|
||||
const event = new CustomEvent('edit', {
|
||||
detail: { name, age, email }
|
||||
})
|
||||
|
||||
// 获取组件根元素并触发事件
|
||||
const rootElement = game.getSceneElement('user-card')
|
||||
if (rootElement) {
|
||||
rootElement.element.dispatchEvent(event)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 插槽(Slots)
|
||||
|
||||
插槽允许父组件向子组件传递内容:
|
||||
|
||||
```html
|
||||
<!-- 子组件 (components/card/index.pe) -->
|
||||
<sence>
|
||||
<box class="card">
|
||||
<box class="card-header">
|
||||
<text class="card-title">{{ title }}</text>
|
||||
</box>
|
||||
<box class="card-body">
|
||||
<!-- 默认插槽 -->
|
||||
<slot></slot>
|
||||
</box>
|
||||
<box class="card-footer">
|
||||
<!-- 具名插槽 -->
|
||||
<slot name="footer"></slot>
|
||||
</box>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
let title = '卡片标题'
|
||||
|
||||
function setTitle(value) {
|
||||
title = value
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
```html
|
||||
<!-- 父组件中使用插槽 -->
|
||||
<sence>
|
||||
<card title="我的卡片">
|
||||
<!-- 默认插槽内容 -->
|
||||
<text>这是卡片的主要内容</text>
|
||||
|
||||
<!-- 具名插槽内容 -->
|
||||
<box slot="footer">
|
||||
<button>确定</button>
|
||||
<button>取消</button>
|
||||
</box>
|
||||
</card>
|
||||
</sence>
|
||||
```
|
||||
|
||||
## 动态组件
|
||||
|
||||
PE支持动态组件,可以根据条件渲染不同的组件:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<!-- 动态组件 -->
|
||||
<component :is="currentComponent"
|
||||
v-for="prop in componentProps"
|
||||
:key="prop.key"
|
||||
v-bind="prop.value">
|
||||
</component>
|
||||
|
||||
<!-- 切换组件的按钮 -->
|
||||
<box class="btn" @click="switchToButton">显示按钮</box>
|
||||
<box class="btn" @click="switchToCard">显示卡片</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
let currentComponent = 'button'
|
||||
let componentProps = {}
|
||||
|
||||
function switchToButton() {
|
||||
currentComponent = 'button'
|
||||
componentProps = { label: '动态按钮' }
|
||||
}
|
||||
|
||||
function switchToCard() {
|
||||
currentComponent = 'card'
|
||||
componentProps = { title: '动态卡片' }
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 组件生命周期
|
||||
|
||||
组件也有自己的生命周期钩子,与场景生命周期类似:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="component">组件内容</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 组件生命周期钩子
|
||||
onLoad(() => {
|
||||
console.log('组件加载')
|
||||
// 组件初始化
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('组件显示')
|
||||
// 组件显示时的操作
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
console.log('组件隐藏')
|
||||
// 组件隐藏时的操作
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
console.log('组件销毁')
|
||||
// 组件销毁时的清理操作
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 组件最佳实践
|
||||
|
||||
### 1. 单一职责原则
|
||||
|
||||
每个组件应该只负责一个功能:
|
||||
|
||||
```html
|
||||
<!-- 好的做法 -->
|
||||
<user-avatar></user-avatar>
|
||||
<user-name></user-name>
|
||||
<user-email></user-email>
|
||||
|
||||
<!-- 避免 -->
|
||||
<user-info></user-info> <!-- 包含太多功能 -->
|
||||
```
|
||||
|
||||
### 2. 合理的组件结构
|
||||
|
||||
```html
|
||||
<!-- components/product-card/index.pe -->
|
||||
<sence>
|
||||
<box class="product-card">
|
||||
<sprite class="product-image"></sprite>
|
||||
<box class="product-info">
|
||||
<text class="product-name">{{ name }}</text>
|
||||
<text class="product-price">¥{{ price }}</text>
|
||||
<box class="product-actions">
|
||||
<button @click="addToCart">加入购物车</button>
|
||||
<button @click="viewDetails">查看详情</button>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 属性
|
||||
let name = ''
|
||||
let price = 0
|
||||
let image = ''
|
||||
|
||||
// 事件
|
||||
let onAddToCart = null
|
||||
let onViewDetails = null
|
||||
|
||||
// 方法
|
||||
function setName(value) {
|
||||
name = value
|
||||
}
|
||||
|
||||
function setPrice(value) {
|
||||
price = value
|
||||
}
|
||||
|
||||
function setImage(value) {
|
||||
image = value
|
||||
}
|
||||
|
||||
function setOnAddToCart(handler) {
|
||||
onAddToCart = handler
|
||||
}
|
||||
|
||||
function setOnViewDetails(handler) {
|
||||
onViewDetails = handler
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
function addToCart() {
|
||||
if (typeof onAddToCart === 'function') {
|
||||
onAddToCart({ name, price })
|
||||
}
|
||||
}
|
||||
|
||||
function viewDetails() {
|
||||
if (typeof onViewDetails === 'function') {
|
||||
onViewDetails({ name, price })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 3. 组件样式隔离
|
||||
|
||||
```less
|
||||
/* components/product-card/index.less */
|
||||
.product-card {
|
||||
width: 300px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
|
||||
.product-image {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.product-info {
|
||||
padding: 15px;
|
||||
|
||||
.product-name {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.product-price {
|
||||
color: #e74c3c;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.product-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
|
||||
.button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
以下是一个完整的组件示例:
|
||||
|
||||
### components/modal/index.pe
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="modal-overlay" @click="handleOverlayClick">
|
||||
<box class="modal-container" @click.stop>
|
||||
<box class="modal-header">
|
||||
<text class="modal-title">{{ title }}</text>
|
||||
<box class="modal-close" @click="close">✕</box>
|
||||
</box>
|
||||
<box class="modal-body">
|
||||
<slot></slot>
|
||||
</box>
|
||||
<box class="modal-footer">
|
||||
<slot name="footer">
|
||||
<button class="btn btn-primary" @click="confirm">确定</button>
|
||||
<button class="btn btn-secondary" @click="close">取消</button>
|
||||
</slot>
|
||||
</box>
|
||||
</box>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 属性
|
||||
let title = '模态框'
|
||||
let visible = false
|
||||
|
||||
// 事件
|
||||
let onConfirm = null
|
||||
let onClose = null
|
||||
|
||||
// 方法
|
||||
function setTitle(value) {
|
||||
title = value
|
||||
const titleElement = game.getSceneElement('modal-title')
|
||||
if (titleElement) {
|
||||
titleElement.element.textContent = title
|
||||
}
|
||||
}
|
||||
|
||||
function setVisible(value) {
|
||||
visible = value
|
||||
const overlay = game.getSceneElement('modal-overlay')
|
||||
if (overlay) {
|
||||
overlay.element.style.display = visible ? 'flex' : 'none'
|
||||
}
|
||||
}
|
||||
|
||||
function setOnConfirm(handler) {
|
||||
onConfirm = handler
|
||||
}
|
||||
|
||||
function setOnClose(handler) {
|
||||
onClose = handler
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
function handleOverlayClick() {
|
||||
close()
|
||||
}
|
||||
|
||||
function confirm() {
|
||||
if (typeof onConfirm === 'function') {
|
||||
onConfirm()
|
||||
}
|
||||
close()
|
||||
}
|
||||
|
||||
function close() {
|
||||
setVisible(false)
|
||||
if (typeof onClose === 'function') {
|
||||
onClose()
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onLoad(() => {
|
||||
console.log('模态框组件加载')
|
||||
// 初始化隐藏
|
||||
setVisible(false)
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('模态框组件显示')
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
console.log('模态框组件隐藏')
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
console.log('模态框组件销毁')
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### components/modal/index.less
|
||||
|
||||
```less
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.modal-container {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
min-width: 300px;
|
||||
max-width: 500px;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.modal-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 20px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 15px 20px;
|
||||
border-top: 1px solid #eee;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
|
||||
.btn {
|
||||
padding: 8px 16px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
|
||||
&.btn-primary {
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-secondary {
|
||||
background-color: #95a5a6;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: #7f8c8d;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 使用模态框组件
|
||||
|
||||
```html
|
||||
<!-- scenes/home/index.pe -->
|
||||
<sence>
|
||||
<box class="page">
|
||||
<button @click="showModal">打开模态框</button>
|
||||
|
||||
<!-- 使用模态框组件 -->
|
||||
<modal title="确认操作" @confirm="handleConfirm" @close="handleClose">
|
||||
<text>您确定要执行此操作吗?</text>
|
||||
<box slot="footer">
|
||||
<button class="btn btn-danger" @click="handleConfirm">确认</button>
|
||||
<button class="btn btn-secondary" @click="handleClose">取消</button>
|
||||
</box>
|
||||
</modal>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
let modalVisible = false
|
||||
|
||||
function showModal() {
|
||||
modalVisible = true
|
||||
// 更新模态框可见性
|
||||
const modal = game.getSceneElement('modal')
|
||||
if (modal) {
|
||||
modal.setVisible(true)
|
||||
}
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
console.log('用户确认操作')
|
||||
// 执行确认操作
|
||||
}
|
||||
|
||||
function handleClose() {
|
||||
console.log('用户关闭模态框')
|
||||
modalVisible = false
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了PE引擎的组件系统。组件是构建复杂应用的基础,合理使用组件可以大大提高代码的可维护性和复用性。
|
||||
84
guide/essentials/README.md
Normal file
84
guide/essentials/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# 基础教程
|
||||
|
||||
在本章节中,你将学习PE引擎的核心概念。我们假定你已经完成了[快速上手](../quick-start)指南,并对HTML、CSS和JavaScript有基本的了解。
|
||||
|
||||
## 目录
|
||||
|
||||
- [创建应用实例](./application)
|
||||
- [元素系统](./elements)
|
||||
- [场景系统](./scenes)
|
||||
- [样式处理](./styling)
|
||||
- [事件处理](./event-handling)
|
||||
- [生命周期](./lifecycle)
|
||||
|
||||
## 什么是PE引擎?
|
||||
|
||||
PE(Pandona Engine)是一个现代化的前端应用开发框架,专注于提供简洁的API和高效的开发体验。它采用编译时架构,支持基于路由表的场景管理,让开发者能够快速构建交互式Web应用。
|
||||
|
||||
PE的核心特性包括:
|
||||
|
||||
1. **基于路由的场景管理**:通过简单的路由配置,轻松管理应用的不同状态和视图。
|
||||
2. **声明式模板语法**:使用类似HTML的模板语法,让代码更直观易懂。
|
||||
3. **组件化开发**:将UI拆分为独立的可复用组件,提高代码的可维护性。
|
||||
4. **内置动画系统**:提供丰富的动画API,轻松实现流畅的交互动画。
|
||||
5. **响应式数据绑定**:自动追踪数据变化,确保UI与数据保持同步。
|
||||
6. **强大的样式系统**:支持CSS预处理器,提供灵活的样式管理方案。
|
||||
|
||||
## 核心概念概览
|
||||
|
||||
在深入了解每个概念之前,让我们先快速了解一下PE引擎的核心概念:
|
||||
|
||||
### 应用实例
|
||||
|
||||
每个PE应用都从创建一个应用实例开始:
|
||||
|
||||
```javascript
|
||||
import PE from 'pe-engine'
|
||||
|
||||
const game = PE.create()
|
||||
```
|
||||
|
||||
这个实例包含了所有PE引擎的功能,是整个应用的核心。
|
||||
|
||||
### 元素系统
|
||||
|
||||
PE提供了丰富的内置元素类型,包括:
|
||||
|
||||
- `sprite`:精灵元素,可用于显示图像或创建基本图形
|
||||
- `box`:盒子元素,用于创建矩形区域
|
||||
- `text`:文本元素,用于显示文本内容
|
||||
- `html`:HTML元素,用于嵌入原生HTML内容
|
||||
- `svg`:SVG元素,用于创建矢量图形
|
||||
|
||||
### 场景系统
|
||||
|
||||
场景是PE应用的基本构建块。每个场景对应一个路由路径,包含:
|
||||
|
||||
- 模板定义(`<sence>`标签)
|
||||
- 样式定义(`.less`文件)
|
||||
- 逻辑代码(`<script>`标签)
|
||||
|
||||
### 样式处理
|
||||
|
||||
PE使用Less作为CSS预处理器,每个场景可以有对应的样式文件。样式会自动作用于场景内的元素,避免全局样式污染。
|
||||
|
||||
### 事件处理
|
||||
|
||||
PE提供简洁的事件绑定语法,通过`@`前缀可以直接在模板中绑定事件处理器:
|
||||
|
||||
```html
|
||||
<box @click="handleClick">点击我</box>
|
||||
```
|
||||
|
||||
### 生命周期
|
||||
|
||||
每个场景都有完整的生命周期钩子,包括:
|
||||
|
||||
- `onLoad`:场景加载时调用
|
||||
- `onShow`:场景显示时调用
|
||||
- `onHide`:场景隐藏时调用
|
||||
- `onDestory`:场景销毁时调用
|
||||
|
||||
这些钩子让你能够在适当的时机执行初始化、清理等操作。
|
||||
|
||||
在接下来的章节中,我们将深入探讨这些概念,帮助你掌握PE引擎的使用方法。
|
||||
194
guide/essentials/application.md
Normal file
194
guide/essentials/application.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# 创建应用实例
|
||||
|
||||
在PE引擎中,所有应用都从创建一个应用实例开始。这个实例是整个应用的核心,包含了引擎的所有功能。
|
||||
|
||||
## 创建应用实例
|
||||
|
||||
要创建一个PE应用实例,你需要从`pe-engine`包中导入PE对象,然后调用`PE.create()`方法:
|
||||
|
||||
```javascript
|
||||
import PE from 'pe-engine'
|
||||
|
||||
// 创建应用实例
|
||||
const game = PE.create()
|
||||
```
|
||||
|
||||
`PE.create()`方法会返回一个引擎实例,该实例包含了所有PE引擎的功能,包括元素创建、场景管理、动画系统等。
|
||||
|
||||
## 应用配置
|
||||
|
||||
在创建应用实例时,你可以传入配置选项来自定义应用的行为:
|
||||
|
||||
```javascript
|
||||
import PE from 'pe-engine'
|
||||
|
||||
// 带配置的应用实例
|
||||
const game = PE.create({
|
||||
width: 1024, // 舞台宽度,默认800
|
||||
height: 768, // 舞台高度,默认600
|
||||
background: '#ffffff', // 舞台背景色,默认'#f0f0f0'
|
||||
fps: 60 // 帧率,默认60
|
||||
})
|
||||
```
|
||||
|
||||
### 配置选项说明
|
||||
|
||||
| 选项 | 类型 | 默认值 | 描述 |
|
||||
|------|------|--------|------|
|
||||
| width | number | 800 | 应用舞台的宽度(像素) |
|
||||
| height | number | 600 | 应用舞台的高度(像素) |
|
||||
| background | string | '#f0f0f0' | 舞台背景色 |
|
||||
| fps | number | 60 | 应用的帧率 |
|
||||
|
||||
## 应用实例的核心功能
|
||||
|
||||
创建的应用实例提供了丰富的API来管理你的应用:
|
||||
|
||||
### 元素创建
|
||||
|
||||
使用`create`方法可以创建各种元素:
|
||||
|
||||
```javascript
|
||||
// 创建精灵
|
||||
const sprite = game.create('sprite')
|
||||
sprite.setPosition(100, 100)
|
||||
sprite.setSize(100, 100)
|
||||
|
||||
// 创建盒子
|
||||
const box = game.create('box', {
|
||||
x: 200,
|
||||
y: 200,
|
||||
width: 150,
|
||||
height: 100
|
||||
})
|
||||
|
||||
// 创建文本
|
||||
const text = game.create('text', {
|
||||
text: 'Hello PE!',
|
||||
x: 300,
|
||||
y: 300
|
||||
})
|
||||
```
|
||||
|
||||
### 场景管理
|
||||
|
||||
应用实例提供了场景管理功能:
|
||||
|
||||
```javascript
|
||||
// 切换到指定路径的场景
|
||||
PE.navigateTo('/about')
|
||||
|
||||
// 预加载场景
|
||||
game.preloadScenes(['/home', '/about', '/contact'])
|
||||
```
|
||||
|
||||
### 动画系统
|
||||
|
||||
应用实例集成了动画系统:
|
||||
|
||||
```javascript
|
||||
// 创建补间动画
|
||||
game.tween(sprite.element)
|
||||
.to({ left: '500px', top: '500px' }, 1000)
|
||||
.easing('easeInOutQuad')
|
||||
.start()
|
||||
|
||||
// 创建帧动画
|
||||
game.createFrameAnimation('walk', [
|
||||
'img/walk1.png',
|
||||
'img/walk2.png',
|
||||
'img/walk3.png'
|
||||
], 10)
|
||||
|
||||
game.playFrameAnimation(sprite, 'walk', true)
|
||||
```
|
||||
|
||||
### 资源管理
|
||||
|
||||
应用实例提供了资源加载和管理功能:
|
||||
|
||||
```javascript
|
||||
// 加载图像资源
|
||||
const image = await game.load('path/to/image.png')
|
||||
|
||||
// 加载音频资源
|
||||
game.loadSound('jump', 'path/to/jump.mp3')
|
||||
game.loadMusic('bgm', 'path/to/background.mp3')
|
||||
```
|
||||
|
||||
### 摄像机控制
|
||||
|
||||
应用实例支持摄像机系统:
|
||||
|
||||
```javascript
|
||||
// 设置摄像机位置
|
||||
game.setCameraPosition(100, 100)
|
||||
|
||||
// 跟随目标
|
||||
game.follow(playerSprite)
|
||||
|
||||
// 摄像机震动效果
|
||||
game.shakeCamera(10, 500)
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
以下是一个完整的应用实例创建和使用示例:
|
||||
|
||||
```javascript
|
||||
import PE from 'pe-engine'
|
||||
|
||||
// 创建应用实例
|
||||
const game = PE.create({
|
||||
width: 800,
|
||||
height: 600,
|
||||
background: '#2c3e50'
|
||||
})
|
||||
|
||||
// 创建一个精灵
|
||||
const player = game.create('sprite')
|
||||
player.setPosition(100, 100)
|
||||
player.setSize(50, 50)
|
||||
|
||||
// 为精灵添加样式
|
||||
player.element.style.backgroundColor = '#3498db'
|
||||
player.element.style.borderRadius = '50%'
|
||||
|
||||
// 添加点击事件
|
||||
player.element.addEventListener('click', () => {
|
||||
// 播放动画
|
||||
game.tween(player.element)
|
||||
.to({
|
||||
left: Math.random() * 700 + 'px',
|
||||
top: Math.random() * 500 + 'px'
|
||||
}, 500)
|
||||
.easing('easeOutQuad')
|
||||
.start()
|
||||
})
|
||||
|
||||
// 添加键盘控制
|
||||
document.addEventListener('keydown', (e) => {
|
||||
const speed = 10
|
||||
const pos = {
|
||||
left: parseInt(player.element.style.left) || 0,
|
||||
top: parseInt(player.element.style.top) || 0
|
||||
}
|
||||
|
||||
switch(e.key) {
|
||||
case 'ArrowUp':
|
||||
player.setPosition(pos.left, pos.top - speed)
|
||||
break
|
||||
case 'ArrowDown':
|
||||
player.setPosition(pos.left, pos.top + speed)
|
||||
break
|
||||
case 'ArrowLeft':
|
||||
player.setPosition(pos.left - speed, pos.top)
|
||||
break
|
||||
case 'ArrowRight':
|
||||
player.setPosition(pos.left + speed, pos.top)
|
||||
break
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了如何创建和配置PE应用实例,以及如何使用其核心功能。在下一章节中,我们将深入探讨PE的元素系统。
|
||||
303
guide/essentials/elements.md
Normal file
303
guide/essentials/elements.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# 元素系统
|
||||
|
||||
PE引擎提供了丰富的内置元素类型,让你能够快速创建各种UI组件和视觉元素。元素是构成PE应用界面的基本单位。
|
||||
|
||||
## 元素类型概览
|
||||
|
||||
PE引擎目前支持以下几种内置元素类型:
|
||||
|
||||
1. **Sprite(精灵)** - 用于显示图像或创建基本图形
|
||||
2. **Box(盒子)** - 用于创建矩形区域
|
||||
3. **Text(文本)** - 用于显示文本内容
|
||||
4. **HTML** - 用于嵌入原生HTML内容
|
||||
5. **SVG** - 用于创建矢量图形
|
||||
|
||||
## 创建元素
|
||||
|
||||
在PE中,所有元素都通过应用实例的`create`方法创建:
|
||||
|
||||
```javascript
|
||||
// 通用创建方法
|
||||
const element = game.create(type, options)
|
||||
```
|
||||
|
||||
### Sprite(精灵)
|
||||
|
||||
Sprite是最常用的元素类型,可以用来显示图像或创建基本图形。
|
||||
|
||||
```javascript
|
||||
// 创建一个默认的sprite
|
||||
const sprite = game.create('sprite')
|
||||
|
||||
// 创建带配置的sprite
|
||||
const spriteWithConfig = game.create('sprite', {
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50
|
||||
})
|
||||
|
||||
// 设置位置和尺寸
|
||||
sprite.setPosition(200, 200)
|
||||
sprite.setSize(100, 100)
|
||||
|
||||
// 添加样式
|
||||
sprite.element.style.backgroundColor = '#3498db'
|
||||
sprite.element.style.borderRadius = '50%'
|
||||
```
|
||||
|
||||
### Box(盒子)
|
||||
|
||||
Box元素用于创建矩形区域,常用于创建按钮、面板等UI组件。
|
||||
|
||||
```javascript
|
||||
// 创建一个box
|
||||
const box = game.create('box', {
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 200,
|
||||
height: 100
|
||||
})
|
||||
|
||||
// Box元素的DOM元素可以直接操作样式
|
||||
box.element.style.backgroundColor = '#e74c3c'
|
||||
box.element.style.borderRadius = '8px'
|
||||
```
|
||||
|
||||
### Text(文本)
|
||||
|
||||
Text元素用于显示文本内容。
|
||||
|
||||
```javascript
|
||||
// 创建文本元素
|
||||
const text = game.create('text', {
|
||||
text: 'Hello PE!',
|
||||
x: 100,
|
||||
y: 100
|
||||
})
|
||||
|
||||
// 更新文本内容
|
||||
text.setText('新的文本内容')
|
||||
|
||||
// 设置文本样式
|
||||
text.element.style.color = '#ffffff'
|
||||
text.element.style.fontSize = '24px'
|
||||
text.element.style.fontWeight = 'bold'
|
||||
```
|
||||
|
||||
### HTML元素
|
||||
|
||||
HTML元素允许你嵌入原生HTML内容。
|
||||
|
||||
```javascript
|
||||
// 创建HTML元素
|
||||
const htmlElement = game.create('html', {
|
||||
html: '<div class="custom-html">这是HTML内容</div>',
|
||||
x: 100,
|
||||
y: 100
|
||||
})
|
||||
|
||||
// 更新HTML内容
|
||||
htmlElement.setHtml('<div class="updated-html">更新的内容</div>')
|
||||
```
|
||||
|
||||
### SVG元素
|
||||
|
||||
SVG元素用于创建矢量图形。
|
||||
|
||||
```javascript
|
||||
// 创建SVG元素
|
||||
const svgElement = game.create('svg', {
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 200,
|
||||
height: 200,
|
||||
content: '<circle cx="100" cy="100" r="50" fill="#3498db" />'
|
||||
})
|
||||
```
|
||||
|
||||
## 元素的通用方法和属性
|
||||
|
||||
所有PE元素都有一些通用的方法和属性:
|
||||
|
||||
### 位置和尺寸
|
||||
|
||||
```javascript
|
||||
// 设置位置
|
||||
element.setPosition(100, 200)
|
||||
|
||||
// 设置尺寸
|
||||
element.setSize(300, 150)
|
||||
|
||||
// 获取位置
|
||||
const x = element.getX()
|
||||
const y = element.getY()
|
||||
|
||||
// 获取尺寸
|
||||
const width = element.getWidth()
|
||||
const height = element.getHeight()
|
||||
```
|
||||
|
||||
### 样式操作
|
||||
|
||||
```javascript
|
||||
// 设置单个样式属性
|
||||
element.setStyle('backgroundColor', '#3498db')
|
||||
|
||||
// 设置多个样式属性
|
||||
element.setStyles({
|
||||
backgroundColor: '#3498db',
|
||||
borderRadius: '8px',
|
||||
border: '2px solid #2980b9'
|
||||
})
|
||||
|
||||
// 添加CSS类
|
||||
element.addClass('my-class')
|
||||
|
||||
// 移除CSS类
|
||||
element.removeClass('my-class')
|
||||
|
||||
// 检查是否包含CSS类
|
||||
if (element.hasClass('my-class')) {
|
||||
// 执行相应操作
|
||||
}
|
||||
```
|
||||
|
||||
### 显示和隐藏
|
||||
|
||||
```javascript
|
||||
// 隐藏元素
|
||||
element.hide()
|
||||
|
||||
// 显示元素
|
||||
element.show()
|
||||
|
||||
// 切换显示状态
|
||||
element.toggle()
|
||||
```
|
||||
|
||||
## 在场景模板中使用元素
|
||||
|
||||
在PE的场景系统中,你也可以直接在模板中定义元素:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<!-- 使用sprite元素 -->
|
||||
<sprite class="player" x="100" y="100" width="50" height="50"></sprite>
|
||||
|
||||
<!-- 使用box元素 -->
|
||||
<box class="panel" x="200" y="200" width="300" height="200">面板内容</box>
|
||||
|
||||
<!-- 使用text元素 -->
|
||||
<text class="title" x="100" y="50">欢迎使用PE引擎</text>
|
||||
|
||||
<!-- 使用循环创建多个元素 -->
|
||||
<box for="{item} in menuItems"
|
||||
class="menu-item"
|
||||
x="{item.x}"
|
||||
y="{item.y}"
|
||||
@click="handleMenuClick(item.id)">
|
||||
{{ item.label }}
|
||||
</box>
|
||||
</sence>
|
||||
```
|
||||
|
||||
对应的样式文件(.less):
|
||||
|
||||
```less
|
||||
.player {
|
||||
background-color: #3498db;
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.player:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.panel {
|
||||
background-color: #ecf0f1;
|
||||
border: 2px solid #bdc3c7;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: #2c3e50;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
margin: 5px 0;
|
||||
}
|
||||
```
|
||||
|
||||
## 元素的事件处理
|
||||
|
||||
PE元素支持丰富的事件处理:
|
||||
|
||||
```javascript
|
||||
// 添加点击事件
|
||||
element.element.addEventListener('click', (event) => {
|
||||
console.log('元素被点击了')
|
||||
})
|
||||
|
||||
// 添加鼠标移入事件
|
||||
element.element.addEventListener('mouseenter', (event) => {
|
||||
element.setStyle('backgroundColor', '#e74c3c')
|
||||
})
|
||||
|
||||
// 添加鼠标移出事件
|
||||
element.element.addEventListener('mouseleave', (event) => {
|
||||
element.setStyle('backgroundColor', '#3498db')
|
||||
})
|
||||
|
||||
// 在场景模板中直接绑定事件
|
||||
// <box @click="handleClick" @mouseenter="handleMouseEnter">点击我</box>
|
||||
```
|
||||
|
||||
## 自定义元素
|
||||
|
||||
除了内置元素,你还可以创建自定义元素:
|
||||
|
||||
```javascript
|
||||
// 创建自定义元素类
|
||||
class CustomElement extends BaseElement {
|
||||
constructor(x, y, width, height, engineId) {
|
||||
super(x, y, width, height, engineId)
|
||||
|
||||
// 初始化自定义元素
|
||||
this.element.style.backgroundColor = '#9b59b6'
|
||||
this.element.style.borderRadius = '10px'
|
||||
}
|
||||
|
||||
// 自定义方法
|
||||
animateColor() {
|
||||
const colors = ['#9b59b6', '#3498db', '#e74c3c', '#2ecc71']
|
||||
let index = 0
|
||||
|
||||
setInterval(() => {
|
||||
this.element.style.backgroundColor = colors[index % colors.length]
|
||||
index++
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 注册自定义元素
|
||||
// 在场景中使用
|
||||
// <custom-element x="100" y="100" width="100" height="100"></custom-element>
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了PE引擎的元素系统。在下一章节中,我们将深入探讨场景系统的使用。
|
||||
605
guide/essentials/event-handling.md
Normal file
605
guide/essentials/event-handling.md
Normal file
@@ -0,0 +1,605 @@
|
||||
# 事件处理
|
||||
|
||||
PE引擎提供了简洁而强大的事件处理机制,让你能够轻松响应用户的交互操作。事件处理是创建交互式应用的关键部分。
|
||||
|
||||
## 事件绑定语法
|
||||
|
||||
在PE的场景模板中,你可以使用`@`前缀直接绑定事件处理器:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<!-- 基本事件绑定 -->
|
||||
<box @click="handleClick">点击我</box>
|
||||
|
||||
<!-- 多个事件绑定 -->
|
||||
<box @click="handleClick" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
|
||||
悬停我
|
||||
</box>
|
||||
|
||||
<!-- 传递参数 -->
|
||||
<box @click="handleClickWithParam('button1')">按钮1</box>
|
||||
<box @click="handleClickWithParam('button2')">按钮2</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleClick() {
|
||||
console.log('元素被点击了')
|
||||
}
|
||||
|
||||
function handleMouseEnter() {
|
||||
console.log('鼠标进入元素')
|
||||
}
|
||||
|
||||
function handleMouseLeave() {
|
||||
console.log('鼠标离开元素')
|
||||
}
|
||||
|
||||
function handleClickWithParam(buttonId) {
|
||||
console.log('点击了按钮:', buttonId)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 支持的事件类型
|
||||
|
||||
PE支持所有标准的DOM事件类型:
|
||||
|
||||
### 鼠标事件
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box @click="handleClick"
|
||||
@dblclick="handleDoubleClick"
|
||||
@mouseenter="handleMouseEnter"
|
||||
@mouseleave="handleMouseLeave"
|
||||
@mousedown="handleMouseDown"
|
||||
@mouseup="handleMouseUp"
|
||||
@contextmenu="handleContextMenu">
|
||||
鼠标事件示例
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleClick(event) {
|
||||
console.log('点击事件:', event)
|
||||
}
|
||||
|
||||
function handleDoubleClick(event) {
|
||||
console.log('双击事件:', event)
|
||||
}
|
||||
|
||||
function handleMouseEnter(event) {
|
||||
console.log('鼠标进入:', event)
|
||||
}
|
||||
|
||||
function handleMouseLeave(event) {
|
||||
console.log('鼠标离开:', event)
|
||||
}
|
||||
|
||||
function handleMouseDown(event) {
|
||||
console.log('鼠标按下:', event)
|
||||
}
|
||||
|
||||
function handleMouseUp(event) {
|
||||
console.log('鼠标释放:', event)
|
||||
}
|
||||
|
||||
function handleContextMenu(event) {
|
||||
event.preventDefault() // 阻止右键菜单
|
||||
console.log('右键点击:', event)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 键盘事件
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<text @keydown="handleKeyDown"
|
||||
@keyup="handleKeyUp"
|
||||
@keypress="handleKeyPress"
|
||||
tabindex="0">
|
||||
按键事件示例(点击后按键盘)
|
||||
</text>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleKeyDown(event) {
|
||||
console.log('按键按下:', event.key, event.code)
|
||||
}
|
||||
|
||||
function handleKeyUp(event) {
|
||||
console.log('按键释放:', event.key, event.code)
|
||||
}
|
||||
|
||||
function handleKeyPress(event) {
|
||||
console.log('按键按压:', event.key)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 表单事件
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<html @input="handleInput"
|
||||
@change="handleChange"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
html="<input type='text' placeholder='输入内容...' />">
|
||||
</html>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleInput(event) {
|
||||
console.log('输入事件:', event.target.value)
|
||||
}
|
||||
|
||||
function handleChange(event) {
|
||||
console.log('值改变事件:', event.target.value)
|
||||
}
|
||||
|
||||
function handleFocus(event) {
|
||||
console.log('获得焦点')
|
||||
}
|
||||
|
||||
function handleBlur(event) {
|
||||
console.log('失去焦点')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 触摸事件
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box @touchstart="handleTouchStart"
|
||||
@touchmove="handleTouchMove"
|
||||
@touchend="handleTouchEnd"
|
||||
@touchcancel="handleTouchCancel">
|
||||
触摸事件示例
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleTouchStart(event) {
|
||||
console.log('触摸开始:', event.touches.length, '个触摸点')
|
||||
}
|
||||
|
||||
function handleTouchMove(event) {
|
||||
console.log('触摸移动:', event.touches[0].clientX, event.touches[0].clientY)
|
||||
}
|
||||
|
||||
function handleTouchEnd(event) {
|
||||
console.log('触摸结束')
|
||||
}
|
||||
|
||||
function handleTouchCancel(event) {
|
||||
console.log('触摸取消')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 事件对象
|
||||
|
||||
所有事件处理器都会接收到一个事件对象,包含有关事件的详细信息:
|
||||
|
||||
```javascript
|
||||
function handleClick(event) {
|
||||
// 事件基本信息
|
||||
console.log('事件类型:', event.type)
|
||||
console.log('目标元素:', event.target)
|
||||
console.log('当前元素:', event.currentTarget)
|
||||
|
||||
// 鼠标位置
|
||||
console.log('页面坐标:', event.pageX, event.pageY)
|
||||
console.log('客户端坐标:', event.clientX, event.clientY)
|
||||
|
||||
// 键盘信息
|
||||
console.log('是否按下Ctrl键:', event.ctrlKey)
|
||||
console.log('是否按下Alt键:', event.altKey)
|
||||
console.log('是否按下Shift键:', event.shiftKey)
|
||||
|
||||
// 阻止默认行为
|
||||
event.preventDefault()
|
||||
|
||||
// 阻止事件冒泡
|
||||
event.stopPropagation()
|
||||
}
|
||||
```
|
||||
|
||||
## 在JavaScript中绑定事件
|
||||
|
||||
除了在模板中绑定事件,你也可以在JavaScript代码中直接绑定事件:
|
||||
|
||||
```javascript
|
||||
// 获取场景元素
|
||||
const element = game.getSceneElement('my-button')
|
||||
|
||||
// 添加事件监听器
|
||||
element.element.addEventListener('click', function(event) {
|
||||
console.log('元素被点击了')
|
||||
})
|
||||
|
||||
// 添加多个事件监听器
|
||||
element.element.addEventListener('mouseenter', handleMouseEnter)
|
||||
element.element.addEventListener('mouseleave', handleMouseLeave)
|
||||
|
||||
// 移除事件监听器
|
||||
element.element.removeEventListener('click', handleClick)
|
||||
```
|
||||
|
||||
## 事件修饰符
|
||||
|
||||
PE支持一些常用的事件修饰符,类似于Vue.js的语法:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<!-- 阻止默认行为 -->
|
||||
<box @click.prevent="handleClick">阻止默认行为</box>
|
||||
|
||||
<!-- 阻止事件冒泡 -->
|
||||
<box @click.stop="handleClick">阻止事件冒泡</box>
|
||||
|
||||
<!-- 只触发一次 -->
|
||||
<box @click.once="handleClick">只触发一次</box>
|
||||
|
||||
<!-- 组合修饰符 -->
|
||||
<box @click.stop.prevent="handleClick">阻止冒泡和默认行为</box>
|
||||
</sence>
|
||||
```
|
||||
|
||||
## 自定义事件
|
||||
|
||||
你也可以创建和触发自定义事件:
|
||||
|
||||
```javascript
|
||||
// 创建自定义事件
|
||||
const customEvent = new CustomEvent('myCustomEvent', {
|
||||
detail: { message: '这是自定义事件数据' }
|
||||
})
|
||||
|
||||
// 触发自定义事件
|
||||
element.element.dispatchEvent(customEvent)
|
||||
|
||||
// 监听自定义事件
|
||||
element.element.addEventListener('myCustomEvent', function(event) {
|
||||
console.log('接收到自定义事件:', event.detail.message)
|
||||
})
|
||||
```
|
||||
|
||||
## 事件总线
|
||||
|
||||
PE引擎内置了事件总线,允许你在不同组件间进行通信:
|
||||
|
||||
```javascript
|
||||
// 发送事件
|
||||
game.eventBus.emit('user-login', { username: 'john' })
|
||||
|
||||
// 监听事件
|
||||
game.eventBus.on('user-login', function(data) {
|
||||
console.log('用户登录:', data.username)
|
||||
})
|
||||
|
||||
// 移除事件监听器
|
||||
game.eventBus.off('user-login', handlerFunction)
|
||||
```
|
||||
|
||||
## 在场景脚本中处理事件
|
||||
|
||||
在场景的`<script>`部分,你可以定义事件处理函数:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="counter-button" @click="incrementCounter">计数器: {{ counter }}</box>
|
||||
<box class="reset-button" @click="resetCounter">重置</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 数据定义
|
||||
let counter = 0
|
||||
|
||||
// 事件处理函数
|
||||
function incrementCounter() {
|
||||
counter++
|
||||
console.log('计数器:', counter)
|
||||
|
||||
// 更新UI
|
||||
const button = game.getSceneElement('counter-button')
|
||||
button.element.textContent = `计数器: ${counter}`
|
||||
}
|
||||
|
||||
function resetCounter() {
|
||||
counter = 0
|
||||
console.log('计数器已重置')
|
||||
|
||||
// 更新UI
|
||||
const button = game.getSceneElement('counter-button')
|
||||
button.element.textContent = `计数器: ${counter}`
|
||||
}
|
||||
|
||||
// 生命周期钩子中绑定事件
|
||||
onLoad(() => {
|
||||
console.log('场景加载完成,计数器初始化为', counter)
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('场景显示,当前计数器值为', counter)
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## 事件处理最佳实践
|
||||
|
||||
### 1. 合理使用事件委托
|
||||
|
||||
对于大量相似元素,使用事件委托可以提高性能:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<!-- 使用事件委托处理列表项点击 -->
|
||||
<box class="list-container" @click="handleListItemClick">
|
||||
<box class="list-item" data-id="1">项目1</box>
|
||||
<box class="list-item" data-id="2">项目2</box>
|
||||
<box class="list-item" data-id="3">项目3</box>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleListItemClick(event) {
|
||||
// 检查点击的是否是列表项
|
||||
if (event.target.classList.contains('list-item')) {
|
||||
const id = event.target.getAttribute('data-id')
|
||||
console.log('点击了项目:', id)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 2. 及时移除事件监听器
|
||||
|
||||
在适当的时机移除事件监听器,避免内存泄漏:
|
||||
|
||||
```javascript
|
||||
onLoad(() => {
|
||||
// 添加事件监听器
|
||||
document.addEventListener('keydown', handleGlobalKeyDown)
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
// 移除事件监听器
|
||||
document.removeEventListener('keydown', handleGlobalKeyDown)
|
||||
})
|
||||
|
||||
function handleGlobalKeyDown(event) {
|
||||
// 全局键盘事件处理
|
||||
if (event.key === 'Escape') {
|
||||
PE.navigateTo('/')
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 使用防抖和节流
|
||||
|
||||
对于频繁触发的事件(如滚动、输入),使用防抖和节流优化性能:
|
||||
|
||||
```javascript
|
||||
// 防抖函数
|
||||
function debounce(func, wait) {
|
||||
let timeout
|
||||
return function(...args) {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => func.apply(this, args), wait)
|
||||
}
|
||||
}
|
||||
|
||||
// 节流函数
|
||||
function throttle(func, limit) {
|
||||
let inThrottle
|
||||
return function(...args) {
|
||||
if (!inThrottle) {
|
||||
func.apply(this, args)
|
||||
inThrottle = true
|
||||
setTimeout(() => inThrottle = false, limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 使用防抖处理输入事件
|
||||
const handleInput = debounce(function(event) {
|
||||
console.log('输入内容:', event.target.value)
|
||||
}, 300)
|
||||
|
||||
// 使用节流处理滚动事件
|
||||
const handleScroll = throttle(function(event) {
|
||||
console.log('页面滚动')
|
||||
}, 100)
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
以下是一个完整的事件处理示例:
|
||||
|
||||
### scenes/game/index.pe
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="game-container">
|
||||
<!-- 玩家角色 -->
|
||||
<sprite class="player"
|
||||
@mousedown="startDrag"
|
||||
@mouseup="stopDrag"
|
||||
@touchstart="startDrag"
|
||||
@touchend="stopDrag">
|
||||
</sprite>
|
||||
|
||||
<!-- 敌人 -->
|
||||
<sprite for="{enemy} in enemies"
|
||||
class="enemy"
|
||||
:class="{ 'enemy-active': enemy.active }"
|
||||
@click="hitEnemy(enemy.id)">
|
||||
</sprite>
|
||||
|
||||
<!-- 控制按钮 -->
|
||||
<box class="control-panel">
|
||||
<box class="btn btn-primary" @click="startGame">开始游戏</box>
|
||||
<box class="btn btn-secondary" @click="pauseGame">暂停</box>
|
||||
<box class="btn btn-danger" @click="resetGame">重置</box>
|
||||
</box>
|
||||
|
||||
<!-- 游戏信息 -->
|
||||
<text class="score">得分: {{ score }}</text>
|
||||
<text class="lives">生命: {{ lives }}</text>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 游戏状态
|
||||
let score = 0
|
||||
let lives = 3
|
||||
let gameRunning = false
|
||||
let dragging = false
|
||||
|
||||
// 敌人数据
|
||||
const enemies = [
|
||||
{ id: 1, active: true },
|
||||
{ id: 2, active: true },
|
||||
{ id: 3, active: true }
|
||||
]
|
||||
|
||||
// 事件处理函数
|
||||
function startDrag(event) {
|
||||
if (!gameRunning) return
|
||||
dragging = true
|
||||
console.log('开始拖拽玩家')
|
||||
|
||||
// 添加鼠标移动事件监听器
|
||||
document.addEventListener('mousemove', handleDrag)
|
||||
document.addEventListener('touchmove', handleDrag)
|
||||
}
|
||||
|
||||
function stopDrag(event) {
|
||||
dragging = false
|
||||
console.log('停止拖拽玩家')
|
||||
|
||||
// 移除鼠标移动事件监听器
|
||||
document.removeEventListener('mousemove', handleDrag)
|
||||
document.removeEventListener('touchmove', handleDrag)
|
||||
}
|
||||
|
||||
function handleDrag(event) {
|
||||
if (!dragging || !gameRunning) return
|
||||
|
||||
const player = game.getSceneElement('player')
|
||||
if (player) {
|
||||
// 获取鼠标或触摸位置
|
||||
let x, y
|
||||
if (event.type === 'touchmove') {
|
||||
x = event.touches[0].clientX
|
||||
y = event.touches[0].clientY
|
||||
} else {
|
||||
x = event.clientX
|
||||
y = event.clientY
|
||||
}
|
||||
|
||||
// 更新玩家位置
|
||||
player.setPosition(x - 25, y - 25) // 考虑精灵尺寸
|
||||
}
|
||||
}
|
||||
|
||||
function hitEnemy(enemyId) {
|
||||
if (!gameRunning) return
|
||||
|
||||
// 找到被击中的敌人
|
||||
const enemy = enemies.find(e => e.id === enemyId)
|
||||
if (enemy && enemy.active) {
|
||||
// 标记敌人为非活跃状态
|
||||
enemy.active = false
|
||||
|
||||
// 增加得分
|
||||
score += 10
|
||||
updateScore()
|
||||
|
||||
console.log('击中敌人:', enemyId)
|
||||
}
|
||||
}
|
||||
|
||||
function startGame() {
|
||||
gameRunning = true
|
||||
score = 0
|
||||
lives = 3
|
||||
updateScore()
|
||||
updateLives()
|
||||
|
||||
// 重置敌人状态
|
||||
enemies.forEach(enemy => {
|
||||
enemy.active = true
|
||||
})
|
||||
|
||||
console.log('游戏开始')
|
||||
}
|
||||
|
||||
function pauseGame() {
|
||||
gameRunning = !gameRunning
|
||||
console.log(gameRunning ? '游戏继续' : '游戏暂停')
|
||||
}
|
||||
|
||||
function resetGame() {
|
||||
gameRunning = false
|
||||
score = 0
|
||||
lives = 3
|
||||
updateScore()
|
||||
updateLives()
|
||||
|
||||
// 重置敌人状态
|
||||
enemies.forEach(enemy => {
|
||||
enemy.active = true
|
||||
})
|
||||
|
||||
console.log('游戏重置')
|
||||
}
|
||||
|
||||
// 更新得分显示
|
||||
function updateScore() {
|
||||
const scoreElement = game.getSceneElement('score')
|
||||
if (scoreElement) {
|
||||
scoreElement.element.textContent = `得分: ${score}`
|
||||
}
|
||||
}
|
||||
|
||||
// 更新生命显示
|
||||
function updateLives() {
|
||||
const livesElement = game.getSceneElement('lives')
|
||||
if (livesElement) {
|
||||
livesElement.element.textContent = `生命: ${lives}`
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期钩子
|
||||
onLoad(() => {
|
||||
console.log('游戏场景加载完成')
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('游戏场景显示')
|
||||
// 初始化游戏状态
|
||||
updateScore()
|
||||
updateLives()
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
console.log('游戏场景隐藏')
|
||||
// 暂停游戏
|
||||
gameRunning = false
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
console.log('游戏场景销毁')
|
||||
// 清理事件监听器
|
||||
document.removeEventListener('mousemove', handleDrag)
|
||||
document.removeEventListener('touchmove', handleDrag)
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了PE引擎的事件处理机制。在下一章节中,我们将探讨生命周期的相关内容。
|
||||
564
guide/essentials/lifecycle.md
Normal file
564
guide/essentials/lifecycle.md
Normal file
@@ -0,0 +1,564 @@
|
||||
# 生命周期
|
||||
|
||||
PE引擎为场景提供了完整的生命周期钩子,让你能够在适当的时机执行初始化、清理和其他操作。理解生命周期对于开发高效、稳定的PE应用至关重要。
|
||||
|
||||
## 生命周期钩子概览
|
||||
|
||||
每个PE场景都有四个主要的生命周期钩子:
|
||||
|
||||
1. **onLoad** - 场景加载时调用(只执行一次)
|
||||
2. **onShow** - 场景显示时调用(每次显示都会执行)
|
||||
3. **onHide** - 场景隐藏时调用
|
||||
4. **onDestory** - 场景销毁时调用(只执行一次)
|
||||
|
||||
## onLoad
|
||||
|
||||
`onLoad`钩子在场景首次加载时调用,只执行一次。这是进行一次性初始化操作的最佳时机。
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="welcome">欢迎来到PE引擎</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 在onLoad中进行一次性初始化
|
||||
onLoad(() => {
|
||||
console.log('场景加载完成')
|
||||
|
||||
// 初始化数据
|
||||
initializeData()
|
||||
|
||||
// 设置初始状态
|
||||
setupInitialState()
|
||||
|
||||
// 加载资源
|
||||
loadResources()
|
||||
|
||||
// 添加全局事件监听器
|
||||
document.addEventListener('keydown', handleGlobalKeyDown)
|
||||
})
|
||||
|
||||
function initializeData() {
|
||||
// 初始化应用数据
|
||||
console.log('初始化数据')
|
||||
}
|
||||
|
||||
function setupInitialState() {
|
||||
// 设置初始状态
|
||||
console.log('设置初始状态')
|
||||
}
|
||||
|
||||
function loadResources() {
|
||||
// 加载必要的资源
|
||||
console.log('加载资源')
|
||||
}
|
||||
|
||||
function handleGlobalKeyDown(event) {
|
||||
// 处理全局键盘事件
|
||||
if (event.key === 'Escape') {
|
||||
PE.navigateTo('/')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## onShow
|
||||
|
||||
`onShow`钩子在场景每次显示时调用。无论是首次显示还是从其他场景切换回来,都会执行此钩子。
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="content">场景内容</box>
|
||||
<text class="last-updated">最后更新: {{ lastUpdated }}</text>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
let lastUpdated = ''
|
||||
|
||||
onShow(() => {
|
||||
console.log('场景显示')
|
||||
|
||||
// 更新时间戳
|
||||
updateTimestamp()
|
||||
|
||||
// 刷新数据
|
||||
refreshData()
|
||||
|
||||
// 启动动画
|
||||
startAnimations()
|
||||
|
||||
// 恢复定时器
|
||||
resumeTimers()
|
||||
})
|
||||
|
||||
function updateTimestamp() {
|
||||
lastUpdated = new Date().toLocaleString()
|
||||
const timeElement = game.getSceneElement('last-updated')
|
||||
if (timeElement) {
|
||||
timeElement.element.textContent = `最后更新: ${lastUpdated}`
|
||||
}
|
||||
}
|
||||
|
||||
function refreshData() {
|
||||
// 刷新场景数据
|
||||
console.log('刷新数据')
|
||||
}
|
||||
|
||||
function startAnimations() {
|
||||
// 启动场景动画
|
||||
console.log('启动动画')
|
||||
}
|
||||
|
||||
function resumeTimers() {
|
||||
// 恢复定时器
|
||||
console.log('恢复定时器')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## onHide
|
||||
|
||||
`onHide`钩子在场景隐藏时调用,比如切换到其他场景时。
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="content">场景内容</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
onHide(() => {
|
||||
console.log('场景隐藏')
|
||||
|
||||
// 暂停动画
|
||||
pauseAnimations()
|
||||
|
||||
// 暂停定时器
|
||||
pauseTimers()
|
||||
|
||||
// 保存状态
|
||||
saveState()
|
||||
})
|
||||
|
||||
function pauseAnimations() {
|
||||
// 暂停场景动画
|
||||
console.log('暂停动画')
|
||||
}
|
||||
|
||||
function pauseTimers() {
|
||||
// 暂停定时器
|
||||
console.log('暂停定时器')
|
||||
}
|
||||
|
||||
function saveState() {
|
||||
// 保存场景状态
|
||||
console.log('保存状态')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## onDestory
|
||||
|
||||
`onDestory`钩子在场景销毁时调用,通常发生在应用关闭或场景被永久移除时。
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="content">场景内容</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
onDestory(() => {
|
||||
console.log('场景销毁')
|
||||
|
||||
// 清理资源
|
||||
cleanupResources()
|
||||
|
||||
// 移除事件监听器
|
||||
removeEventListeners()
|
||||
|
||||
// 停止所有动画
|
||||
stopAllAnimations()
|
||||
|
||||
// 清理定时器
|
||||
clearAllTimers()
|
||||
})
|
||||
|
||||
function cleanupResources() {
|
||||
// 清理加载的资源
|
||||
console.log('清理资源')
|
||||
}
|
||||
|
||||
function removeEventListeners() {
|
||||
// 移除添加的事件监听器
|
||||
document.removeEventListener('keydown', handleGlobalKeyDown)
|
||||
console.log('移除事件监听器')
|
||||
}
|
||||
|
||||
function stopAllAnimations() {
|
||||
// 停止所有动画
|
||||
console.log('停止所有动画')
|
||||
}
|
||||
|
||||
function clearAllTimers() {
|
||||
// 清理所有定时器
|
||||
console.log('清理定时器')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 生命周期执行顺序
|
||||
|
||||
理解生命周期钩子的执行顺序对于正确管理场景状态非常重要:
|
||||
|
||||
### 首次加载场景
|
||||
|
||||
1. `onLoad` - 场景加载时执行(一次)
|
||||
2. `onShow` - 场景显示时执行
|
||||
|
||||
### 切换到其他场景
|
||||
|
||||
1. 当前场景: `onHide` - 场景隐藏时执行
|
||||
|
||||
### 切换回场景
|
||||
|
||||
1. `onShow` - 场景显示时执行
|
||||
|
||||
### 销毁场景
|
||||
|
||||
1. `onHide` - 场景隐藏时执行(如果当前显示)
|
||||
2. `onDestory` - 场景销毁时执行(一次)
|
||||
|
||||
## 实际应用示例
|
||||
|
||||
以下是一个完整的生命周期应用示例:
|
||||
|
||||
### scenes/dashboard/index.pe
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="dashboard">
|
||||
<text class="title">仪表板</text>
|
||||
<text class="status">状态: {{ status }}</text>
|
||||
<text class="last-update">最后更新: {{ lastUpdate }}</text>
|
||||
|
||||
<box class="data-container">
|
||||
<box for="{item} in dataItems" class="data-card">
|
||||
<text class="card-title">{{ item.title }}</text>
|
||||
<text class="card-value">{{ item.value }}</text>
|
||||
</box>
|
||||
</box>
|
||||
|
||||
<box class="controls">
|
||||
<box class="btn btn-primary" @click="refreshData">刷新数据</box>
|
||||
<box class="btn btn-secondary" @click="PE.navigateTo('/settings')">设置</box>
|
||||
</box>
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 数据状态
|
||||
let status = '加载中...'
|
||||
let lastUpdate = ''
|
||||
let dataItems = []
|
||||
let refreshTimer = null
|
||||
let dataRefreshInterval = null
|
||||
|
||||
// onLoad - 只执行一次
|
||||
onLoad(() => {
|
||||
console.log('仪表板加载')
|
||||
|
||||
// 初始化数据
|
||||
initializeData()
|
||||
|
||||
// 设置全局事件监听器
|
||||
setupEventListeners()
|
||||
|
||||
// 加载初始数据
|
||||
loadData()
|
||||
})
|
||||
|
||||
// onShow - 每次显示时执行
|
||||
onShow(() => {
|
||||
console.log('仪表板显示')
|
||||
|
||||
// 更新状态
|
||||
updateStatus('运行中')
|
||||
|
||||
// 启动定时刷新
|
||||
startAutoRefresh()
|
||||
|
||||
// 恢复动画
|
||||
resumeAnimations()
|
||||
})
|
||||
|
||||
// onHide - 隐藏时执行
|
||||
onHide(() => {
|
||||
console.log('仪表板隐藏')
|
||||
|
||||
// 暂停自动刷新
|
||||
stopAutoRefresh()
|
||||
|
||||
// 暂停动画
|
||||
pauseAnimations()
|
||||
|
||||
// 保存当前状态
|
||||
saveCurrentState()
|
||||
})
|
||||
|
||||
// onDestory - 销毁时执行
|
||||
onDestory(() => {
|
||||
console.log('仪表板销毁')
|
||||
|
||||
// 清理所有资源
|
||||
cleanup()
|
||||
})
|
||||
|
||||
// 初始化数据
|
||||
function initializeData() {
|
||||
dataItems = [
|
||||
{ title: '用户数', value: '0' },
|
||||
{ title: '订单数', value: '0' },
|
||||
{ title: '收入', value: '¥0' }
|
||||
]
|
||||
|
||||
updateUI()
|
||||
}
|
||||
|
||||
// 设置事件监听器
|
||||
function setupEventListeners() {
|
||||
// 监听网络状态变化
|
||||
window.addEventListener('online', handleOnline)
|
||||
window.addEventListener('offline', handleOffline)
|
||||
}
|
||||
|
||||
// 加载数据
|
||||
async function loadData() {
|
||||
try {
|
||||
updateStatus('加载数据中...')
|
||||
|
||||
// 模拟API调用
|
||||
const data = await fetchDataFromAPI()
|
||||
|
||||
dataItems = data
|
||||
lastUpdate = new Date().toLocaleString()
|
||||
|
||||
updateStatus('数据加载完成')
|
||||
updateUI()
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
updateStatus('数据加载失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟API调用
|
||||
function fetchDataFromAPI() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve([
|
||||
{ title: '用户数', value: Math.floor(Math.random() * 1000) },
|
||||
{ title: '订单数', value: Math.floor(Math.random() * 500) },
|
||||
{ title: '收入', value: '¥' + (Math.random() * 10000).toFixed(2) }
|
||||
])
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
|
||||
// 启动自动刷新
|
||||
function startAutoRefresh() {
|
||||
if (dataRefreshInterval) {
|
||||
clearInterval(dataRefreshInterval)
|
||||
}
|
||||
|
||||
dataRefreshInterval = setInterval(() => {
|
||||
loadData()
|
||||
}, 30000) // 每30秒刷新一次
|
||||
|
||||
// 启动更新时间戳定时器
|
||||
if (refreshTimer) {
|
||||
clearInterval(refreshTimer)
|
||||
}
|
||||
|
||||
refreshTimer = setInterval(() => {
|
||||
updateTimestamp()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 停止自动刷新
|
||||
function stopAutoRefresh() {
|
||||
if (dataRefreshInterval) {
|
||||
clearInterval(dataRefreshInterval)
|
||||
dataRefreshInterval = null
|
||||
}
|
||||
|
||||
if (refreshTimer) {
|
||||
clearInterval(refreshTimer)
|
||||
refreshTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
// 更新状态显示
|
||||
function updateStatus(newStatus) {
|
||||
status = newStatus
|
||||
const statusElement = game.getSceneElement('status')
|
||||
if (statusElement) {
|
||||
statusElement.element.textContent = `状态: ${status}`
|
||||
}
|
||||
}
|
||||
|
||||
// 更新时间戳显示
|
||||
function updateTimestamp() {
|
||||
if (lastUpdate) {
|
||||
const timeElement = game.getSceneElement('last-update')
|
||||
if (timeElement) {
|
||||
const elapsed = Math.floor((new Date() - new Date(lastUpdate)) / 1000)
|
||||
timeElement.element.textContent = `最后更新: ${lastUpdate} (${elapsed}秒前)`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新UI
|
||||
function updateUI() {
|
||||
// 更新数据卡片
|
||||
const container = game.getSceneElement('data-container')
|
||||
if (container) {
|
||||
// 清空现有内容
|
||||
container.element.innerHTML = ''
|
||||
|
||||
// 添加新的数据卡片
|
||||
dataItems.forEach(item => {
|
||||
const card = document.createElement('div')
|
||||
card.className = 'data-card'
|
||||
card.innerHTML = `
|
||||
<div class="card-title">${item.title}</div>
|
||||
<div class="card-value">${item.value}</div>
|
||||
`
|
||||
container.element.appendChild(card)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新数据
|
||||
function refreshData() {
|
||||
loadData()
|
||||
}
|
||||
|
||||
// 处理在线状态
|
||||
function handleOnline() {
|
||||
updateStatus('在线')
|
||||
}
|
||||
|
||||
// 处理离线状态
|
||||
function handleOffline() {
|
||||
updateStatus('离线')
|
||||
}
|
||||
|
||||
// 恢复动画
|
||||
function resumeAnimations() {
|
||||
console.log('恢复动画')
|
||||
}
|
||||
|
||||
// 暂停动画
|
||||
function pauseAnimations() {
|
||||
console.log('暂停动画')
|
||||
}
|
||||
|
||||
// 保存当前状态
|
||||
function saveCurrentState() {
|
||||
console.log('保存当前状态')
|
||||
}
|
||||
|
||||
// 清理资源
|
||||
function cleanup() {
|
||||
// 停止所有定时器
|
||||
stopAutoRefresh()
|
||||
|
||||
// 移除事件监听器
|
||||
window.removeEventListener('online', handleOnline)
|
||||
window.removeEventListener('offline', handleOffline)
|
||||
|
||||
// 清理数据
|
||||
dataItems = []
|
||||
status = ''
|
||||
lastUpdate = ''
|
||||
|
||||
console.log('资源清理完成')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## 生命周期最佳实践
|
||||
|
||||
### 1. 合理分配操作到不同钩子
|
||||
|
||||
```javascript
|
||||
// 正确的做法
|
||||
onLoad(() => {
|
||||
// 一次性初始化操作
|
||||
initializeDatabase()
|
||||
setupGlobalEventListeners()
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
// 每次显示时的操作
|
||||
startDataPolling()
|
||||
resumeAnimations()
|
||||
})
|
||||
|
||||
onHide(() => {
|
||||
// 隐藏时的操作
|
||||
stopDataPolling()
|
||||
pauseAnimations()
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
// 销毁时的操作
|
||||
cleanupResources()
|
||||
removeEventListeners()
|
||||
})
|
||||
```
|
||||
|
||||
### 2. 及时清理资源
|
||||
|
||||
```javascript
|
||||
onLoad(() => {
|
||||
// 创建定时器
|
||||
this.timer = setInterval(updateData, 5000)
|
||||
|
||||
// 添加事件监听器
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
// 清理定时器
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
this.timer = null
|
||||
}
|
||||
|
||||
// 移除事件监听器
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
```
|
||||
|
||||
### 3. 处理异步操作
|
||||
|
||||
```javascript
|
||||
onLoad(async () => {
|
||||
try {
|
||||
// 异步加载数据
|
||||
this.data = await loadDataFromServer()
|
||||
updateUI()
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
showErrorMessage()
|
||||
}
|
||||
})
|
||||
|
||||
onDestory(() => {
|
||||
// 取消未完成的请求
|
||||
if (this.currentRequest) {
|
||||
this.currentRequest.cancel()
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了PE引擎的生命周期机制。这些生命周期钩子为你提供了强大的控制能力,让你能够精确管理场景的创建、显示、隐藏和销毁过程。
|
||||
377
guide/essentials/scenes.md
Normal file
377
guide/essentials/scenes.md
Normal file
@@ -0,0 +1,377 @@
|
||||
# 场景系统
|
||||
|
||||
PE引擎的场景系统是其核心特性之一,它提供了一种结构化的方式来组织和管理应用的不同视图和状态。每个场景都是一个独立的单元,包含模板、样式和逻辑代码。
|
||||
|
||||
## 场景的基本结构
|
||||
|
||||
PE场景由三个主要部分组成:
|
||||
|
||||
1. **模板(Template)** - 定义场景的结构和元素
|
||||
2. **样式(Style)** - 定义场景的外观和样式
|
||||
3. **脚本(Script)** - 定义场景的逻辑和行为
|
||||
|
||||
### 场景文件结构
|
||||
|
||||
一个典型的PE场景目录结构如下:
|
||||
|
||||
```
|
||||
scenes/
|
||||
├── home/
|
||||
│ ├── index.pe # 场景模板文件
|
||||
│ └── index.less # 场景样式文件
|
||||
└── about/
|
||||
├── index.pe
|
||||
└── index.less
|
||||
```
|
||||
|
||||
## 场景模板文件(.pe)
|
||||
|
||||
场景模板文件使用类似HTML的语法,包含`sence`标签和`script`标签:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<!-- 场景元素定义 -->
|
||||
<sprite class="logo"></sprite>
|
||||
<box class="welcome-box">欢迎来到PE引擎!</box>
|
||||
<text class="description">这是一个简单的场景示例</text>
|
||||
|
||||
<!-- 循环渲染元素 -->
|
||||
<box for="{item} in menuItems"
|
||||
class="menu-item"
|
||||
@click="handleMenuClick(item.id)">
|
||||
{{ item.label }}
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 场景数据和逻辑
|
||||
const menuItems = [
|
||||
{ id: 'home', label: '首页' },
|
||||
{ id: 'about', label: '关于' },
|
||||
{ id: 'contact', label: '联系' }
|
||||
]
|
||||
|
||||
// 生命周期钩子
|
||||
onLoad(() => {
|
||||
console.log('场景加载完成')
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('场景显示')
|
||||
})
|
||||
|
||||
// 事件处理函数
|
||||
function handleMenuClick(id) {
|
||||
console.log('点击了菜单项:', id)
|
||||
PE.navigateTo(`/${id}`)
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 模板语法
|
||||
|
||||
PE场景模板支持以下语法特性:
|
||||
|
||||
#### 元素定义
|
||||
|
||||
```html
|
||||
<!-- 基本元素 -->
|
||||
<sprite class="my-sprite" x="100" y="100" width="50" height="50"></sprite>
|
||||
<box class="my-box">盒子内容</box>
|
||||
<text class="my-text">文本内容</text>
|
||||
```
|
||||
|
||||
#### 事件绑定
|
||||
|
||||
使用`@`前缀绑定事件处理器:
|
||||
|
||||
```html
|
||||
<box @click="handleClick" @mouseenter="handleMouseEnter">点击我</box>
|
||||
```
|
||||
|
||||
#### 循环渲染
|
||||
|
||||
使用`for`指令循环渲染元素:
|
||||
|
||||
```html
|
||||
<box for="{item} in items" class="item">{{ item.name }}</box>
|
||||
```
|
||||
|
||||
#### 插值表达式
|
||||
|
||||
使用双大括号语法插入数据:
|
||||
|
||||
```html
|
||||
<text>当前计数: {{ count }}</text>
|
||||
```
|
||||
|
||||
## 场景样式文件(.less)
|
||||
|
||||
每个场景可以有对应的Less样式文件,样式会自动作用于该场景内的元素:
|
||||
|
||||
```less
|
||||
// home/index.less
|
||||
.logo {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: #3498db;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.welcome-box {
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
top: 200px;
|
||||
left: 50px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: #7f8c8d;
|
||||
font-size: 16px;
|
||||
position: absolute;
|
||||
top: 320px;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
left: 50px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
// 使用Less变量和嵌套
|
||||
&:hover {
|
||||
background-color: darken(#e74c3c, 10%);
|
||||
}
|
||||
|
||||
&:nth-child(1) { top: 380px; }
|
||||
&:nth-child(2) { top: 430px; }
|
||||
&:nth-child(3) { top: 480px; }
|
||||
}
|
||||
```
|
||||
|
||||
## 场景路由配置
|
||||
|
||||
场景通过`sences.json`文件进行路由配置:
|
||||
|
||||
```json
|
||||
{
|
||||
"sence": [
|
||||
{
|
||||
"path": "/",
|
||||
"title": "首页"
|
||||
},
|
||||
{
|
||||
"path": "/about",
|
||||
"title": "关于我们"
|
||||
},
|
||||
{
|
||||
"path": "/products",
|
||||
"title": "产品"
|
||||
}
|
||||
],
|
||||
"platform": "PC"
|
||||
}
|
||||
```
|
||||
|
||||
## 场景生命周期
|
||||
|
||||
每个场景都有完整的生命周期钩子,让你能够在适当的时机执行操作:
|
||||
|
||||
### onLoad
|
||||
|
||||
场景加载时调用,只在场景首次加载时执行一次:
|
||||
|
||||
```javascript
|
||||
onLoad(() => {
|
||||
console.log('场景加载完成')
|
||||
// 初始化操作
|
||||
initializeData()
|
||||
})
|
||||
```
|
||||
|
||||
### onShow
|
||||
|
||||
场景显示时调用,每次场景被显示时都会执行:
|
||||
|
||||
```javascript
|
||||
onShow(() => {
|
||||
console.log('场景显示')
|
||||
// 每次显示时的操作
|
||||
refreshData()
|
||||
})
|
||||
```
|
||||
|
||||
### onHide
|
||||
|
||||
场景隐藏时调用:
|
||||
|
||||
```javascript
|
||||
onHide(() => {
|
||||
console.log('场景隐藏')
|
||||
// 清理操作
|
||||
pauseAnimations()
|
||||
})
|
||||
```
|
||||
|
||||
### onDestory
|
||||
|
||||
场景销毁时调用:
|
||||
|
||||
```javascript
|
||||
onDestory(() => {
|
||||
console.log('场景销毁')
|
||||
// 最终清理操作
|
||||
clearInterval(timer)
|
||||
})
|
||||
```
|
||||
|
||||
## 场景间导航
|
||||
|
||||
PE提供了简单的API来在场景间进行导航:
|
||||
|
||||
```javascript
|
||||
// 导航到指定路径的场景
|
||||
PE.navigateTo('/about')
|
||||
|
||||
// 在模板中使用
|
||||
<box @click="PE.navigateTo('/products')">查看产品</box>
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
以下是一个完整的场景示例:
|
||||
|
||||
### scenes/product/index.pe
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="header">产品列表</box>
|
||||
|
||||
<box for="{product} in products"
|
||||
class="product-card"
|
||||
@click="viewProduct(product.id)">
|
||||
<text class="product-name">{{ product.name }}</text>
|
||||
<text class="product-price">¥{{ product.price }}</text>
|
||||
</box>
|
||||
|
||||
<box class="back-button" @click="PE.navigateTo('/')">返回首页</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
// 产品数据
|
||||
const products = [
|
||||
{ id: 1, name: '产品A', price: 99.99 },
|
||||
{ id: 2, name: '产品B', price: 149.99 },
|
||||
{ id: 3, name: '产品C', price: 199.99 }
|
||||
]
|
||||
|
||||
// 生命周期钩子
|
||||
onLoad(() => {
|
||||
console.log('产品页面加载')
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('产品页面显示')
|
||||
})
|
||||
|
||||
// 事件处理函数
|
||||
function viewProduct(id) {
|
||||
console.log('查看产品:', id)
|
||||
// 可以通过全局变量或事件传递数据
|
||||
window.currentProductId = id
|
||||
PE.navigateTo('/product-detail')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### scenes/product/index.less
|
||||
|
||||
```less
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
background-color: #34495e;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.product-card {
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
background-color: #ecf0f1;
|
||||
border: 1px solid #bdc3c7;
|
||||
border-radius: 8px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 0 20px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #d5dbdb;
|
||||
}
|
||||
|
||||
&:nth-child(2) { top: 100px; } // 第一个产品卡
|
||||
&:nth-child(3) { top: 220px; } // 第二个产品卡
|
||||
&:nth-child(4) { top: 340px; } // 第三个产品卡
|
||||
}
|
||||
|
||||
.product-name {
|
||||
color: #2c3e50;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.product-price {
|
||||
color: #e74c3c;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
width: 100px;
|
||||
height: 40px;
|
||||
background-color: #95a5a6;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: #7f8c8d;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了PE引擎的场景系统。在下一章节中,我们将探讨样式处理的相关内容。
|
||||
546
guide/essentials/styling.md
Normal file
546
guide/essentials/styling.md
Normal file
@@ -0,0 +1,546 @@
|
||||
# 样式处理
|
||||
|
||||
PE引擎使用Less作为CSS预处理器,提供了强大而灵活的样式管理方案。每个场景可以有对应的样式文件,确保样式的作用域隔离和可维护性。
|
||||
|
||||
## Less预处理器
|
||||
|
||||
Less是一种向后兼容CSS的语言扩展,为CSS添加了变量、嵌套、混合等功能,让样式编写更加高效和可维护。
|
||||
|
||||
### 变量
|
||||
|
||||
使用变量来存储常用的值:
|
||||
|
||||
```less
|
||||
// 定义变量
|
||||
@primary-color: #3498db;
|
||||
@secondary-color: #2ecc71;
|
||||
@font-size-large: 18px;
|
||||
@border-radius: 4px;
|
||||
|
||||
// 使用变量
|
||||
.header {
|
||||
background-color: @primary-color;
|
||||
font-size: @font-size-large;
|
||||
border-radius: @border-radius;
|
||||
}
|
||||
```
|
||||
|
||||
### 嵌套
|
||||
|
||||
Less支持嵌套语法,让样式结构更清晰:
|
||||
|
||||
```less
|
||||
.navbar {
|
||||
background-color: #34495e;
|
||||
|
||||
// 嵌套选择器
|
||||
.nav-item {
|
||||
color: white;
|
||||
padding: 10px 15px;
|
||||
|
||||
// 伪类嵌套
|
||||
&:hover {
|
||||
background-color: #2c3e50;
|
||||
}
|
||||
|
||||
// 子元素嵌套
|
||||
.icon {
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 混合(Mixins)
|
||||
|
||||
混合允许你定义可复用的样式块:
|
||||
|
||||
```less
|
||||
// 定义混合
|
||||
.border-radius(@radius: 4px) {
|
||||
border-radius: @radius;
|
||||
-webkit-border-radius: @radius;
|
||||
-moz-border-radius: @radius;
|
||||
}
|
||||
|
||||
.box-shadow(@x: 0, @y: 0, @blur: 10px, @color: rgba(0,0,0,0.1)) {
|
||||
box-shadow: @arguments;
|
||||
-webkit-box-shadow: @arguments;
|
||||
-moz-box-shadow: @arguments;
|
||||
}
|
||||
|
||||
// 使用混合
|
||||
.button {
|
||||
.border-radius(8px);
|
||||
.box-shadow(0, 2px, 5px, rgba(0,0,0,0.2));
|
||||
}
|
||||
```
|
||||
|
||||
### 函数
|
||||
|
||||
Less提供了丰富的内置函数:
|
||||
|
||||
```less
|
||||
// 颜色函数
|
||||
.button {
|
||||
background-color: #3498db;
|
||||
// 变暗10%
|
||||
&:hover {
|
||||
background-color: darken(#3498db, 10%);
|
||||
}
|
||||
// 变亮10%
|
||||
&:active {
|
||||
background-color: lighten(#3498db, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
// 数学函数
|
||||
.progress-bar {
|
||||
width: percentage(0.5); // 50%
|
||||
height: unit(20, px); // 20px
|
||||
}
|
||||
```
|
||||
|
||||
## 场景样式隔离
|
||||
|
||||
PE引擎确保每个场景的样式只作用于该场景内的元素,避免样式冲突。
|
||||
|
||||
### 样式作用域
|
||||
|
||||
每个场景的样式文件会自动包装在特定的选择器中:
|
||||
|
||||
```less
|
||||
/* scenes/home/index.less */
|
||||
// 原始样式
|
||||
.welcome-box {
|
||||
background-color: #3498db;
|
||||
}
|
||||
|
||||
// 实际生成的样式
|
||||
[data-scene-id="pe-scene-1634567890-abc123"] .welcome-box {
|
||||
background-color: #3498db;
|
||||
}
|
||||
```
|
||||
|
||||
### 全局样式
|
||||
|
||||
你可以在项目根目录创建全局样式文件:
|
||||
|
||||
```less
|
||||
/* styles/base.less */
|
||||
// 全局变量
|
||||
@primary-color: #3498db;
|
||||
@secondary-color: #2ecc71;
|
||||
@text-color: #2c3e50;
|
||||
@bg-color: #ecf0f1;
|
||||
|
||||
// 全局重置样式
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
color: @text-color;
|
||||
background-color: @bg-color;
|
||||
}
|
||||
|
||||
// 全局工具类
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
```
|
||||
|
||||
在主文件中引入全局样式:
|
||||
|
||||
```javascript
|
||||
// main.js
|
||||
import './styles/base.less'
|
||||
import PE from 'pe-engine'
|
||||
```
|
||||
|
||||
## 样式组织最佳实践
|
||||
|
||||
### 按功能组织样式
|
||||
|
||||
```less
|
||||
/* styles/components.less */
|
||||
// 按钮组件
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
|
||||
&.btn-primary {
|
||||
background-color: @primary-color;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: darken(@primary-color, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-secondary {
|
||||
background-color: @secondary-color;
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: darken(@secondary-color, 10%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 卡片组件
|
||||
.card {
|
||||
background-color: white;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
.box-shadow();
|
||||
|
||||
.card-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 响应式样式
|
||||
|
||||
使用媒体查询创建响应式设计:
|
||||
|
||||
```less
|
||||
/* styles/responsive.less */
|
||||
// 响应式断点变量
|
||||
@screen-sm: 576px;
|
||||
@screen-md: 768px;
|
||||
@screen-lg: 992px;
|
||||
@screen-xl: 1200px;
|
||||
|
||||
// 媒体查询混合
|
||||
.responsive(@rules) {
|
||||
@media (max-width: @screen-sm) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
.responsive-md(@rules) {
|
||||
@media (min-width: @screen-md) {
|
||||
@rules();
|
||||
}
|
||||
}
|
||||
|
||||
// 响应式网格系统
|
||||
.container {
|
||||
width: 100%;
|
||||
padding: 0 15px;
|
||||
margin: 0 auto;
|
||||
|
||||
.responsive({
|
||||
max-width: 100%;
|
||||
});
|
||||
|
||||
.responsive-md({
|
||||
max-width: 750px;
|
||||
});
|
||||
|
||||
@media (min-width: @screen-lg) {
|
||||
max-width: 970px;
|
||||
}
|
||||
|
||||
@media (min-width: @screen-xl) {
|
||||
max-width: 1170px;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 动态样式
|
||||
|
||||
PE支持在运行时动态修改样式:
|
||||
|
||||
### 通过JavaScript修改样式
|
||||
|
||||
```javascript
|
||||
// 获取场景元素
|
||||
const element = game.getSceneElement('my-element')
|
||||
|
||||
// 修改单个样式属性
|
||||
element.setStyle('backgroundColor', '#e74c3c')
|
||||
|
||||
// 修改多个样式属性
|
||||
element.setStyles({
|
||||
backgroundColor: '#3498db',
|
||||
color: 'white',
|
||||
fontSize: '18px'
|
||||
})
|
||||
|
||||
// 添加/移除CSS类
|
||||
element.addClass('active')
|
||||
element.removeClass('inactive')
|
||||
```
|
||||
|
||||
### 条件样式
|
||||
|
||||
在场景脚本中根据条件动态应用样式:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="status-box" :class="{ 'status-online': isOnline, 'status-offline': !isOnline }">
|
||||
状态: {{ isOnline ? '在线' : '离线' }}
|
||||
</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
let isOnline = false
|
||||
|
||||
// 模拟状态变化
|
||||
setInterval(() => {
|
||||
isOnline = !isOnline
|
||||
}, 5000)
|
||||
|
||||
onShow(() => {
|
||||
// 根据状态更新样式
|
||||
const statusBox = game.getSceneElement('status-box')
|
||||
if (isOnline) {
|
||||
statusBox.setStyles({
|
||||
backgroundColor: '#2ecc71',
|
||||
color: 'white'
|
||||
})
|
||||
} else {
|
||||
statusBox.setStyles({
|
||||
backgroundColor: '#e74c3c',
|
||||
color: 'white'
|
||||
})
|
||||
}
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
## CSS自定义属性(CSS变量)
|
||||
|
||||
PE也支持使用CSS自定义属性:
|
||||
|
||||
```less
|
||||
/* styles/theme.less */
|
||||
:root {
|
||||
--primary-color: #3498db;
|
||||
--secondary-color: #2ecc71;
|
||||
--text-color: #2c3e50;
|
||||
--bg-color: #ecf0f1;
|
||||
}
|
||||
|
||||
.themed-element {
|
||||
background-color: var(--primary-color);
|
||||
color: var(--text-color);
|
||||
|
||||
&:hover {
|
||||
background-color: var(--secondary-color);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 样式调试
|
||||
|
||||
### 开发者工具
|
||||
|
||||
在浏览器开发者工具中,你可以看到PE为每个场景生成的特定选择器:
|
||||
|
||||
```css
|
||||
/* 实际生成的样式 */
|
||||
[data-scene-id="pe-scene-1634567890-abc123"] .welcome-box {
|
||||
background-color: #3498db;
|
||||
}
|
||||
```
|
||||
|
||||
### 样式覆盖
|
||||
|
||||
如果需要覆盖场景样式,可以使用更具体的选择器:
|
||||
|
||||
```less
|
||||
/* 覆盖特定场景的样式 */
|
||||
[data-scene-id="pe-scene-1634567890-abc123"] .welcome-box {
|
||||
background-color: #e74c3c !important;
|
||||
}
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
|
||||
以下是一个完整的样式处理示例:
|
||||
|
||||
### styles/variables.less
|
||||
|
||||
```less
|
||||
// 颜色变量
|
||||
@colors: {
|
||||
primary: #3498db;
|
||||
secondary: #2ecc71;
|
||||
success: #27ae60;
|
||||
warning: #f39c12;
|
||||
danger: #e74c3c;
|
||||
info: #3498db;
|
||||
light: #f8f9fa;
|
||||
dark: #343a40;
|
||||
}
|
||||
|
||||
// 尺寸变量
|
||||
@sizes: {
|
||||
xs: 0.25rem;
|
||||
sm: 0.5rem;
|
||||
md: 1rem;
|
||||
lg: 1.5rem;
|
||||
xl: 3rem;
|
||||
}
|
||||
|
||||
// 字体变量
|
||||
@fonts: {
|
||||
family: 'Helvetica Neue', Arial, sans-serif;
|
||||
size-base: 16px;
|
||||
size-sm: 0.875rem;
|
||||
size-lg: 1.25rem;
|
||||
weight-normal: 400;
|
||||
weight-bold: 700;
|
||||
}
|
||||
```
|
||||
|
||||
### styles/mixins.less
|
||||
|
||||
```less
|
||||
// 清除浮动
|
||||
.clearfix() {
|
||||
&::after {
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
// 文本省略
|
||||
.text-ellipsis() {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
// 三角形
|
||||
.triangle(@direction: down, @size: 5px, @color: #000) {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-style: solid;
|
||||
|
||||
when (@direction = up) {
|
||||
border-width: 0 @size @size @size;
|
||||
border-color: transparent transparent @color transparent;
|
||||
}
|
||||
|
||||
when (@direction = down) {
|
||||
border-width: @size @size 0 @size;
|
||||
border-color: @color transparent transparent transparent;
|
||||
}
|
||||
|
||||
when (@direction = left) {
|
||||
border-width: @size @size @size 0;
|
||||
border-color: transparent @color transparent transparent;
|
||||
}
|
||||
|
||||
when (@direction = right) {
|
||||
border-width: @size 0 @size @size;
|
||||
border-color: transparent transparent transparent @color;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### scenes/dashboard/index.less
|
||||
|
||||
```less
|
||||
@import '../../styles/variables.less';
|
||||
@import '../../styles/mixins.less';
|
||||
|
||||
.dashboard {
|
||||
padding: @sizes[md];
|
||||
.clearfix();
|
||||
|
||||
.header {
|
||||
margin-bottom: @sizes[lg];
|
||||
|
||||
.title {
|
||||
font-size: @fonts[size-lg];
|
||||
font-weight: @fonts[weight-bold];
|
||||
color: @colors[dark];
|
||||
.text-ellipsis();
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: @fonts[size-sm];
|
||||
color: lighten(@colors[dark], 30%);
|
||||
}
|
||||
}
|
||||
|
||||
.stats-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: @sizes[md];
|
||||
margin-bottom: @sizes[lg];
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
background-color: white;
|
||||
border-radius: @sizes[sm];
|
||||
padding: @sizes[md];
|
||||
.box-shadow(0, 2px, 8px, rgba(0,0,0,0.1));
|
||||
|
||||
.stat-value {
|
||||
font-size: 2rem;
|
||||
font-weight: @fonts[weight-bold];
|
||||
color: @colors[primary];
|
||||
margin-bottom: @sizes[sm];
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: @fonts[size-sm];
|
||||
color: lighten(@colors[dark], 40%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
background-color: white;
|
||||
border-radius: @sizes[sm];
|
||||
padding: @sizes[md];
|
||||
.box-shadow(0, 2px, 8px, rgba(0,0,0,0.1));
|
||||
|
||||
.chart-title {
|
||||
font-size: @fonts[size-base];
|
||||
font-weight: @fonts[weight-bold];
|
||||
margin-bottom: @sizes[md];
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.stats-container {
|
||||
flex-direction: column;
|
||||
|
||||
.stat-card {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
通过以上内容,你已经了解了PE引擎的样式处理机制。在下一章节中,我们将探讨事件处理的相关内容。
|
||||
169
guide/introduction.md
Normal file
169
guide/introduction.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# 简介
|
||||
|
||||
你正在阅读的是 Pandona Engine (PE) 的文档!
|
||||
|
||||
PE 是一款用于构建 2D 游戏和动画的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发 2D 游戏和动画。无论是简单的互动动画还是复杂的 2D 游戏,PE 都可以胜任。
|
||||
|
||||
下面是一个最基本的示例:
|
||||
|
||||
```javascript
|
||||
import PE from 'PE'
|
||||
|
||||
// 创建游戏实例
|
||||
const game = PE.create()
|
||||
|
||||
// 创建一个精灵元素
|
||||
const sprite = game.create('sprite', {
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50
|
||||
})
|
||||
|
||||
// 将精灵添加到游戏中
|
||||
game.addGameObject(sprite)
|
||||
```
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<sprite class="my-sprite" @click="handleClick"></sprite>
|
||||
<box class="my-box">Hello PE!</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleClick() {
|
||||
console.log('Sprite clicked!')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
**结果展示**
|
||||
|
||||
上面的示例展示了 PE 的核心功能:
|
||||
|
||||
- **声明式渲染**:PE 基于标准 HTML 拓展了一套模板语法,使得我们可以声明式地描述游戏场景和元素。
|
||||
- **响应性**:PE 会自动跟踪游戏状态并在其发生变化时响应式地更新渲染。
|
||||
- **组件化**:PE 支持基于场景的组件化开发,每个场景可以包含多个元素。
|
||||
|
||||
## 什么是 PE?
|
||||
|
||||
PE (Pandona Engine) 是一款用于构建 2D 游戏和动画的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发 2D 游戏和动画。
|
||||
|
||||
## 渐进式框架
|
||||
|
||||
PE 是一个框架,也是一个生态。其功能覆盖了大部分 2D 游戏和动画开发常见的需求。但游戏开发世界是十分多样化的,不同的开发者在构建的东西可能在形式和规模上会有很大的不同。考虑到这一点,PE 的设计非常注重灵活性和"可以被逐步集成"这个特点。根据你的需求场景,你可以用不同的方式使用 PE:
|
||||
|
||||
- 无需构建步骤,渐进式增强静态的 HTML
|
||||
- 在任何页面中作为 Web Components 嵌入
|
||||
- 单场景应用 (SSA)
|
||||
- 全屏 / 画布渲染 (CSR)
|
||||
- 开发桌面端、移动端 2D 游戏
|
||||
|
||||
## 场景组件
|
||||
|
||||
在大多数 PE 项目中,我们可以使用一种类似 HTML 格式的文件来书写游戏场景,它被称为**场景文件** (也被称为 `*.pe` 文件)。顾名义,PE 的场景文件会将一个场景的逻辑 (JavaScript),模板 (HTML) 和样式 (CSS) 封装在同一个文件里。下面我们将用场景文件的格式重写上面的示例:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<sprite class="my-sprite" @click="handleClick"></sprite>
|
||||
<box class="my-box">Hello PE!</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
function handleClick() {
|
||||
console.log('Sprite clicked!')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.my-sprite {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-color: blue;
|
||||
}
|
||||
.my-box {
|
||||
color: white;
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
场景文件是 PE 的标志性功能。你可以使用它来编写游戏场景。你可以在后续相关章节里了解更多关于场景文件的用法及用途。
|
||||
|
||||
## API 风格
|
||||
|
||||
PE 的场景可以按两种不同的风格书写:**模板式 API** 和 **编程式 API**。
|
||||
|
||||
### 模板式 API (Template API)
|
||||
|
||||
使用模板式 API,我们可以在 `.pe` 文件中使用类似 HTML 的语法来描述场景元素,并在 `<script>` 标签中编写逻辑代码。
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<sprite class="my-sprite" @click="increment"></sprite>
|
||||
<text class="counter">Count is: {{ count }}</text>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
let count = 0
|
||||
|
||||
function increment() {
|
||||
count++
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
### 编程式 API (Programmatic API)
|
||||
|
||||
通过编程式 API,我们可以使用 JavaScript 代码直接创建和管理游戏元素。
|
||||
|
||||
```javascript
|
||||
import PE from 'PE'
|
||||
|
||||
// 创建游戏实例
|
||||
const game = PE.create()
|
||||
|
||||
// 创建响应式状态
|
||||
let count = 0
|
||||
|
||||
// 创建精灵元素
|
||||
const sprite = game.create('sprite', {
|
||||
x: 100,
|
||||
y: 100,
|
||||
width: 50,
|
||||
height: 50
|
||||
})
|
||||
|
||||
// 添加点击事件
|
||||
sprite.element.addEventListener('click', () => {
|
||||
count++
|
||||
})
|
||||
|
||||
// 将精灵添加到游戏中
|
||||
game.addGameObject(sprite)
|
||||
```
|
||||
|
||||
### 该选哪一个?
|
||||
|
||||
两种 API 风格都能够覆盖大部分的游戏开发场景。它们只是同一个底层系统所提供的两套不同的接口。
|
||||
|
||||
模板式 API 以"场景"的概念为中心,对于有 Web 开发背景的用户来说,这通常与基于 HTML 的心智模型更为一致。同时,它将渲染相关的细节抽象出来,并强制按照模板和脚本的方式来组织代码,从而对初学者而言更为友好。
|
||||
|
||||
编程式 API 的核心思想是直接使用 JavaScript 代码来创建和管理游戏元素。这种形式更加自由,也需要你对 PE 的系统有更深的理解才能高效使用。相应的,它的灵活性也使得组织和重用游戏逻辑的模式变得更加强大。
|
||||
|
||||
如果你是使用 PE 的新手,这里是我们的大致建议:
|
||||
|
||||
- 在学习的过程中,推荐采用更易于自己理解的风格。再强调一下,大部分的核心概念在这两种风格之间都是通用的。熟悉了一种风格以后,你也能够很快地理解另一种风格。
|
||||
- 在生产项目中:
|
||||
- 当你不需要使用构建工具,或者打算主要在低复杂度的场景中使用 PE,推荐采用模板式 API。
|
||||
- 当你打算用 PE 构建完整的游戏项目,推荐采用编程式 API。
|
||||
|
||||
在学习阶段,你不必只固守一种风格。在接下来的文档中我们会为你提供一系列两种风格的代码供你参考。
|
||||
|
||||
## 还有其他问题?
|
||||
|
||||
请查看我们的 FAQ。
|
||||
|
||||
## 选择你的学习路径
|
||||
|
||||
不同的开发者有不同的学习方式。尽管在可能的情况下,我们推荐你通读所有内容,但你还是可以自由地选择一种自己喜欢的学习路径!
|
||||
216
guide/quick-start.md
Normal file
216
guide/quick-start.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# 快速上手
|
||||
|
||||
本指南将帮助你快速开始使用PE引擎创建你的第一个应用。
|
||||
|
||||
## 创建一个简单的PE应用
|
||||
|
||||
### 1. 安装
|
||||
|
||||
首先,创建一个新的项目目录并初始化npm:
|
||||
|
||||
```bash
|
||||
mkdir my-pe-app
|
||||
cd my-pe-app
|
||||
npm init -y
|
||||
```
|
||||
|
||||
然后安装PE引擎:
|
||||
|
||||
```bash
|
||||
npm install pe-engine
|
||||
```
|
||||
|
||||
### 2. 创建HTML文件
|
||||
|
||||
在项目根目录下创建`index.html`文件:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>我的PE应用</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 3. 创建主JavaScript文件
|
||||
|
||||
创建`main.js`文件:
|
||||
|
||||
```javascript
|
||||
import PE from 'pe-engine'
|
||||
|
||||
// 创建应用实例
|
||||
const { game } = PE.create()
|
||||
|
||||
// 添加一个简单的精灵
|
||||
const sprite = game.create('sprite')
|
||||
sprite.setPosition(100, 100)
|
||||
sprite.setSize(100, 100)
|
||||
|
||||
// 设置精灵样式
|
||||
sprite.element.style.backgroundColor = '#3498db'
|
||||
sprite.element.style.borderRadius = '50%'
|
||||
```
|
||||
|
||||
### 4. 启动开发服务器
|
||||
|
||||
安装Vite作为开发服务器:
|
||||
|
||||
```bash
|
||||
npm install -D vite
|
||||
```
|
||||
|
||||
在`package.json`中添加脚本:
|
||||
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
启动开发服务器:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
现在你应该能在浏览器中看到一个蓝色的圆形精灵了!
|
||||
|
||||
## 使用场景系统
|
||||
|
||||
PE引擎提供了强大的场景系统,让你可以轻松管理不同的应用状态。
|
||||
|
||||
### 1. 创建场景目录结构
|
||||
|
||||
```
|
||||
project/
|
||||
├── index.html
|
||||
├── main.js
|
||||
├── scenes/
|
||||
│ ├── home/
|
||||
│ │ ├── index.pe
|
||||
│ │ └── index.less
|
||||
│ └── about/
|
||||
│ ├── index.pe
|
||||
│ └── index.less
|
||||
└── styles/
|
||||
└── base.less
|
||||
```
|
||||
|
||||
### 2. 创建场景配置文件
|
||||
|
||||
创建`scenes.json`文件来定义路由:
|
||||
|
||||
```json
|
||||
{
|
||||
"scenes": [
|
||||
{
|
||||
"path": "/",
|
||||
"title": "主页"
|
||||
},
|
||||
{
|
||||
"path": "/about",
|
||||
"title": "关于"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 创建场景文件
|
||||
|
||||
创建`scenes/home/index.pe`:
|
||||
|
||||
```html
|
||||
<sence>
|
||||
<box class="welcome-box">欢迎来到PE引擎!</box>
|
||||
<sprite class="logo"></sprite>
|
||||
<box class="nav-button" @click="PE.navigateTo('/about')">关于我们</box>
|
||||
</sence>
|
||||
|
||||
<script>
|
||||
onLoad(() => {
|
||||
console.log('主页加载完成')
|
||||
})
|
||||
|
||||
onShow(() => {
|
||||
console.log('主页显示')
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
创建`scenes/home/index.less`:
|
||||
|
||||
```less
|
||||
.welcome-box {
|
||||
width: 300px;
|
||||
height: 100px;
|
||||
background-color: #2c3e50;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
position: absolute;
|
||||
top: 100px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
background-color: #3498db;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
top: 250px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.nav-button {
|
||||
width: 200px;
|
||||
height: 50px;
|
||||
background-color: #e74c3c;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
bottom: 100px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. 更新主文件
|
||||
|
||||
更新`main.js`以使用场景系统:
|
||||
|
||||
```javascript
|
||||
import './styles/base.less'
|
||||
import PE from 'pe-engine'
|
||||
|
||||
// PE引擎会自动加载scenes.json中的路由配置
|
||||
// 并根据路由显示相应的场景
|
||||
```
|
||||
|
||||
现在你已经创建了一个基本的PE应用,它使用场景系统来管理不同的视图。
|
||||
|
||||
## 下一步
|
||||
|
||||
- 阅读[基础教程](./essentials/)了解PE引擎的核心概念
|
||||
- 查看[API参考](./api/)了解所有可用的API
|
||||
- 探索[进阶主题](./advanced/)学习更高级的功能
|
||||
12
index.html
Normal file
12
index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pandona Engine</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
335
index.js
335
index.js
@@ -1,217 +1,142 @@
|
||||
class BaseElement {
|
||||
constructor(elementType = 'div', engineId) {
|
||||
this.element = document.createElement(elementType)
|
||||
this.element.style.position = 'absolute'
|
||||
this.engineId = engineId
|
||||
this.x = 0
|
||||
this.y = 0
|
||||
this.width = 0
|
||||
this.height = 0
|
||||
}
|
||||
// 创建框架入口文件
|
||||
import Engine from './src/core/Engine.js';
|
||||
import SimplifiedEngine, { PE } from './src/core/SimplifiedEngine.js';
|
||||
|
||||
setPosition(x = 0, y = 0) {
|
||||
this.element.style.left = `${x}px`
|
||||
this.element.style.top = `${y}px`
|
||||
this.x = x
|
||||
this.y = y
|
||||
}
|
||||
// 导入所有类以便外部使用
|
||||
import BaseElement from './src/elements/BaseElement.js';
|
||||
import Sprite from './src/elements/Sprite.js';
|
||||
import Box from './src/elements/Box.js';
|
||||
import TextElement from './src/elements/TextElement.js';
|
||||
import HtmlElement from './src/elements/HtmlElement.js';
|
||||
import SvgElement from './src/elements/SvgElement.js';
|
||||
import GameObject from './src/elements/GameObject.js';
|
||||
import { Component, PhysicsComponent, ColliderComponent, AnimationComponent, InputComponent, LifecycleComponent } from './src/elements/Component.js';
|
||||
|
||||
setSize(width = 0, height = 0) {
|
||||
if (width) {
|
||||
this.element.style.width = typeof width === 'number' ? `${width}px` : width
|
||||
this.width = width
|
||||
}
|
||||
if (height) {
|
||||
this.element.style.height = typeof height === 'number' ? `${height}px` : height
|
||||
this.height = height
|
||||
}
|
||||
}
|
||||
// 导入简化版元素类
|
||||
import { SimplifiedSprite, SimplifiedBox, SimplifiedText, SimplifiedHtml, SimplifiedSvg } from './src/elements/SimplifiedElements.js';
|
||||
import { SimplifiedGameObject, SimplifiedComponentFactory, SimplifiedGameObjectFactory } from './src/elements/SimplifiedGameObject.js';
|
||||
|
||||
setStyle(style) {
|
||||
Object.assign(this.element.style, style)
|
||||
}
|
||||
import EventBus from './src/utils/EventBus.js';
|
||||
import { SimplifiedEventBus, eventBus, EVENTS } from './src/utils/SimplifiedEventBus.js';
|
||||
|
||||
add(child) {
|
||||
child && this.element.appendChild(child.element || child)
|
||||
}
|
||||
import ResourceManager from './src/managers/ResourceManager.js';
|
||||
import SceneManager from './src/managers/SceneManager.js';
|
||||
import AudioManager from './src/managers/AudioManager.js';
|
||||
import Camera from './src/managers/Camera.js';
|
||||
|
||||
remove(child) {
|
||||
child && this.element.removeChild(child.element || child)
|
||||
}
|
||||
// 导入简化版管理器
|
||||
import { SimplifiedResourceManager } from './src/managers/SimplifiedResourceManager.js';
|
||||
import { SimplifiedSceneManager } from './src/managers/SimplifiedSceneManager.js';
|
||||
import { SimplifiedAudioManager } from './src/managers/SimplifiedAudioManager.js';
|
||||
import { SimplifiedCamera } from './src/managers/SimplifiedCamera.js';
|
||||
|
||||
on(event, callback) {
|
||||
this.element.addEventListener(event, callback)
|
||||
}
|
||||
import Tween from './src/animation/Tween.js';
|
||||
import AnimationSystem from './src/animation/AnimationSystem.js';
|
||||
import AnimationController from './src/animation/AnimationController.js';
|
||||
import { SimplifiedAnimation } from './src/animation/SimplifiedAnimation.js';
|
||||
|
||||
off(event, callback) {
|
||||
this.element.removeEventListener(event, callback)
|
||||
}
|
||||
import { Particle, ParticleEmitter, ParticleSystem } from './src/effects/ParticleSystem.js';
|
||||
import { SimplifiedParticleSystem, SimplifiedParticleEmitter, SimplifiedParticleFactory } from './src/effects/SimplifiedParticleSystem.js';
|
||||
|
||||
hide() {
|
||||
this.element.style.display = 'none'
|
||||
}
|
||||
import { UIElement, UIButton, UILabel, UIImage, UISlider, UIManager } from './src/ui/UI.js';
|
||||
import { SimplifiedUIManager, SimplifiedButton, SimplifiedLabel, SimplifiedImage, SimplifiedSlider } from './src/ui/SimplifiedUI.js';
|
||||
|
||||
show() {
|
||||
this.element.style.display = 'block'
|
||||
}
|
||||
}
|
||||
import { SimplifiedComponent, SimplifiedPhysicsComponent, SimplifiedColliderComponent, SimplifiedAnimationComponent, SimplifiedInputComponent, SimplifiedLifecycleComponent, SimplifiedComponentFactory as ComponentFactory } from './src/elements/SimplifiedComponent.js';
|
||||
|
||||
class Sprite extends BaseElement {
|
||||
constructor(img, x, y, width, height, engineId) {
|
||||
super('div', engineId)
|
||||
this.imgElement = document.createElement('img')
|
||||
this.imgElement.src = img.src
|
||||
this.imgElement.style.cssText = '-webkit-user-drag: none; user-drag: none;'
|
||||
this.element.appendChild(this.imgElement)
|
||||
// 导出所有类以便外部使用
|
||||
export {
|
||||
// 核心类
|
||||
Engine,
|
||||
SimplifiedEngine,
|
||||
|
||||
// 元素类
|
||||
BaseElement,
|
||||
Sprite,
|
||||
Box,
|
||||
TextElement,
|
||||
HtmlElement,
|
||||
SvgElement,
|
||||
GameObject,
|
||||
|
||||
// 简化版元素类
|
||||
SimplifiedSprite,
|
||||
SimplifiedBox,
|
||||
SimplifiedText,
|
||||
SimplifiedHtml,
|
||||
SimplifiedSvg,
|
||||
|
||||
// 游戏对象类
|
||||
SimplifiedGameObject,
|
||||
SimplifiedGameObjectFactory,
|
||||
|
||||
// 组件类
|
||||
Component,
|
||||
PhysicsComponent,
|
||||
ColliderComponent,
|
||||
AnimationComponent,
|
||||
InputComponent,
|
||||
LifecycleComponent,
|
||||
|
||||
// 简化版组件类
|
||||
SimplifiedComponent,
|
||||
SimplifiedPhysicsComponent,
|
||||
SimplifiedColliderComponent,
|
||||
SimplifiedAnimationComponent,
|
||||
SimplifiedInputComponent,
|
||||
SimplifiedLifecycleComponent,
|
||||
SimplifiedComponentFactory,
|
||||
ComponentFactory,
|
||||
|
||||
// 工具类
|
||||
EventBus,
|
||||
SimplifiedEventBus,
|
||||
eventBus,
|
||||
EVENTS,
|
||||
|
||||
// 管理器
|
||||
ResourceManager,
|
||||
SceneManager,
|
||||
AudioManager,
|
||||
Camera,
|
||||
|
||||
// 简化版管理器
|
||||
SimplifiedResourceManager,
|
||||
SimplifiedSceneManager,
|
||||
SimplifiedAudioManager,
|
||||
SimplifiedCamera,
|
||||
|
||||
// 动画系统
|
||||
Tween,
|
||||
AnimationSystem,
|
||||
AnimationController,
|
||||
SimplifiedAnimation,
|
||||
|
||||
// 特效系统
|
||||
Particle,
|
||||
ParticleEmitter,
|
||||
ParticleSystem,
|
||||
SimplifiedParticleSystem,
|
||||
SimplifiedParticleEmitter,
|
||||
SimplifiedParticleFactory,
|
||||
|
||||
// UI系统
|
||||
UIElement,
|
||||
UIButton,
|
||||
UILabel,
|
||||
UIImage,
|
||||
UISlider,
|
||||
UIManager,
|
||||
SimplifiedUIManager,
|
||||
SimplifiedButton,
|
||||
SimplifiedLabel,
|
||||
SimplifiedImage,
|
||||
SimplifiedSlider,
|
||||
|
||||
// 简化版全局对象
|
||||
PE
|
||||
};
|
||||
|
||||
this.setPosition(x, y)
|
||||
this.setSize(width, height)
|
||||
this.element.setAttribute('data-sprite-id', engineId)
|
||||
// 设置全局变量(可选)
|
||||
window.PE = PE;
|
||||
|
||||
// 精灵特有方法
|
||||
this.name = name => this.element.setAttribute('data-name', name)
|
||||
this.animate = keyframes => (this.element.style.animation = keyframes)
|
||||
}
|
||||
}
|
||||
|
||||
class Box extends BaseElement {
|
||||
constructor(x, y, width, height, engineId) {
|
||||
super('div', engineId)
|
||||
this.setPosition(x, y)
|
||||
this.setSize(width, height)
|
||||
this.element.setAttribute('data-box-id', engineId)
|
||||
}
|
||||
}
|
||||
|
||||
class TextElement extends BaseElement {
|
||||
constructor(text, x, y, engineId) {
|
||||
super('div', engineId)
|
||||
this.element.innerText = text
|
||||
this.setPosition(x, y)
|
||||
this.element.setAttribute('data-text-id', engineId)
|
||||
|
||||
// 文本特有方法
|
||||
this.set = text => (this.element.innerText = text)
|
||||
this.setColor = color => (this.element.style.color = color)
|
||||
this.setFont = font => (this.element.style.font = font)
|
||||
}
|
||||
}
|
||||
|
||||
class HtmlElement extends BaseElement {
|
||||
constructor(html, x, y, engineId) {
|
||||
super('div', engineId)
|
||||
this.element.innerHTML = html
|
||||
this.setPosition(x, y)
|
||||
this.element.setAttribute('data-html-id', engineId)
|
||||
|
||||
// HTML特有方法
|
||||
this.set = html => (this.element.innerHTML = html)
|
||||
this.get = () => this.element.innerHTML
|
||||
this.getSize = () => {
|
||||
const rect = this.element.getBoundingClientRect()
|
||||
return { width: rect.width, height: rect.height }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SvgElement extends BaseElement {
|
||||
constructor(x, y, width, height, content, engineId) {
|
||||
super('div', engineId)
|
||||
this.element.innerHTML = content
|
||||
this.setPosition(x, y)
|
||||
this.setSize(width, height)
|
||||
this.element.setAttribute('data-svg-id', engineId)
|
||||
|
||||
// SVG特有方法
|
||||
this.setContent = content => (this.element.innerHTML = content)
|
||||
}
|
||||
}
|
||||
|
||||
class Engine {
|
||||
constructor(element = document.body, options = {}) {
|
||||
const defaultOptions = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
background: 'transparent',
|
||||
}
|
||||
|
||||
this.options = { ...defaultOptions, ...options }
|
||||
this.images = []
|
||||
this.width = this.options.width
|
||||
this.height = this.options.height
|
||||
this.element = typeof element === 'string' ? document.querySelector(element) : element
|
||||
this.id = Date.now().toString(16)
|
||||
|
||||
this.createStage()
|
||||
}
|
||||
|
||||
createStage() {
|
||||
this.stage = document.createElement('div')
|
||||
this.stage.setAttribute('data-engine-id', this.id)
|
||||
|
||||
Object.assign(this.stage.style, {
|
||||
width: `${this.options.width}px`,
|
||||
height: `${this.options.height}px`,
|
||||
position: 'relative',
|
||||
userSelect: 'none',
|
||||
overflow: 'hidden',
|
||||
background: this.options.background,
|
||||
transform: 'translateZ(0)',
|
||||
})
|
||||
|
||||
// 添加舞台操作方法
|
||||
this.stage.add = child => child && this.stage.appendChild(child.element || child)
|
||||
this.stage.remove = child => child && this.stage.removeChild(child.element || child)
|
||||
|
||||
this.element.appendChild(this.stage)
|
||||
}
|
||||
|
||||
load(src = '') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.src = src
|
||||
img.onload = () => resolve(img)
|
||||
img.onerror = reject
|
||||
this.images.push(img)
|
||||
})
|
||||
}
|
||||
|
||||
createSprite(img, x = 0, y = 0, width = 0, height = 0) {
|
||||
return new Sprite(img, x, y, width, height, this.id)
|
||||
}
|
||||
|
||||
createBox(x = 0, y = 0, width = 0, height = 0) {
|
||||
return new Box(x, y, width, height, this.id)
|
||||
}
|
||||
|
||||
createText(text = '', x = 0, y = 0) {
|
||||
return new TextElement(text, x, y, this.id)
|
||||
}
|
||||
|
||||
createHtml(html = '', x = 0, y = 0) {
|
||||
return new HtmlElement(html, x, y, this.id)
|
||||
}
|
||||
|
||||
createSvg(x = 0, y = 0, width = 0, height = 0, content = '') {
|
||||
return new SvgElement(x, y, width, height, content, this.id)
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this.stage && this.stage.parentNode) {
|
||||
this.stage.parentNode.removeChild(this.stage)
|
||||
}
|
||||
|
||||
// 清理所有图像引用
|
||||
this.images.forEach(img => {
|
||||
img.onload = null
|
||||
img.onerror = null
|
||||
img.src = ''
|
||||
})
|
||||
|
||||
// 清除所有引用
|
||||
this.images = []
|
||||
this.stage = null
|
||||
this.element = null
|
||||
this.options = null
|
||||
}
|
||||
}
|
||||
export default Engine;
|
||||
16
node_modules/.bin/acorn
generated
vendored
Normal file
16
node_modules/.bin/acorn
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../acorn/bin/acorn" "$@"
|
||||
else
|
||||
exec node "$basedir/../acorn/bin/acorn" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/acorn.cmd
generated
vendored
Normal file
17
node_modules/.bin/acorn.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\acorn\bin\acorn" %*
|
||||
28
node_modules/.bin/acorn.ps1
generated
vendored
Normal file
28
node_modules/.bin/acorn.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../acorn/bin/acorn" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../acorn/bin/acorn" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../acorn/bin/acorn" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../acorn/bin/acorn" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/errno
generated
vendored
Normal file
16
node_modules/.bin/errno
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../errno/cli.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../errno/cli.js" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/errno.cmd
generated
vendored
Normal file
17
node_modules/.bin/errno.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\errno\cli.js" %*
|
||||
28
node_modules/.bin/errno.ps1
generated
vendored
Normal file
28
node_modules/.bin/errno.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../errno/cli.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../errno/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../errno/cli.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../errno/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/esbuild
generated
vendored
Normal file
16
node_modules/.bin/esbuild
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../esbuild/bin/esbuild" "$@"
|
||||
else
|
||||
exec node "$basedir/../esbuild/bin/esbuild" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/esbuild.cmd
generated
vendored
Normal file
17
node_modules/.bin/esbuild.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\esbuild\bin\esbuild" %*
|
||||
28
node_modules/.bin/esbuild.ps1
generated
vendored
Normal file
28
node_modules/.bin/esbuild.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../esbuild/bin/esbuild" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../esbuild/bin/esbuild" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../esbuild/bin/esbuild" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/image-size
generated
vendored
Normal file
16
node_modules/.bin/image-size
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../image-size/bin/image-size.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../image-size/bin/image-size.js" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/image-size.cmd
generated
vendored
Normal file
17
node_modules/.bin/image-size.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\image-size\bin\image-size.js" %*
|
||||
28
node_modules/.bin/image-size.ps1
generated
vendored
Normal file
28
node_modules/.bin/image-size.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../image-size/bin/image-size.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../image-size/bin/image-size.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../image-size/bin/image-size.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../image-size/bin/image-size.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/lessc
generated
vendored
Normal file
16
node_modules/.bin/lessc
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../less/bin/lessc" "$@"
|
||||
else
|
||||
exec node "$basedir/../less/bin/lessc" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/lessc.cmd
generated
vendored
Normal file
17
node_modules/.bin/lessc.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\less\bin\lessc" %*
|
||||
28
node_modules/.bin/lessc.ps1
generated
vendored
Normal file
28
node_modules/.bin/lessc.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../less/bin/lessc" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../less/bin/lessc" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../less/bin/lessc" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../less/bin/lessc" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/mime
generated
vendored
Normal file
16
node_modules/.bin/mime
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../mime/cli.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../mime/cli.js" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/mime.cmd
generated
vendored
Normal file
17
node_modules/.bin/mime.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\mime\cli.js" %*
|
||||
28
node_modules/.bin/mime.ps1
generated
vendored
Normal file
28
node_modules/.bin/mime.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../mime/cli.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../mime/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../mime/cli.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../mime/cli.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/nanoid
generated
vendored
Normal file
16
node_modules/.bin/nanoid
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../nanoid/bin/nanoid.cjs" "$@"
|
||||
else
|
||||
exec node "$basedir/../nanoid/bin/nanoid.cjs" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/nanoid.cmd
generated
vendored
Normal file
17
node_modules/.bin/nanoid.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\nanoid\bin\nanoid.cjs" %*
|
||||
28
node_modules/.bin/nanoid.ps1
generated
vendored
Normal file
28
node_modules/.bin/nanoid.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../nanoid/bin/nanoid.cjs" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/needle
generated
vendored
Normal file
16
node_modules/.bin/needle
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../needle/bin/needle" "$@"
|
||||
else
|
||||
exec node "$basedir/../needle/bin/needle" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/needle.cmd
generated
vendored
Normal file
17
node_modules/.bin/needle.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\needle\bin\needle" %*
|
||||
28
node_modules/.bin/needle.ps1
generated
vendored
Normal file
28
node_modules/.bin/needle.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../needle/bin/needle" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../needle/bin/needle" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../needle/bin/needle" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../needle/bin/needle" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/rollup
generated
vendored
Normal file
16
node_modules/.bin/rollup
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../rollup/dist/bin/rollup" "$@"
|
||||
else
|
||||
exec node "$basedir/../rollup/dist/bin/rollup" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/rollup.cmd
generated
vendored
Normal file
17
node_modules/.bin/rollup.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\rollup\dist\bin\rollup" %*
|
||||
28
node_modules/.bin/rollup.ps1
generated
vendored
Normal file
28
node_modules/.bin/rollup.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../rollup/dist/bin/rollup" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../rollup/dist/bin/rollup" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../rollup/dist/bin/rollup" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../rollup/dist/bin/rollup" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/semver
generated
vendored
Normal file
16
node_modules/.bin/semver
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../semver/bin/semver" "$@"
|
||||
else
|
||||
exec node "$basedir/../semver/bin/semver" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/semver.cmd
generated
vendored
Normal file
17
node_modules/.bin/semver.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\semver\bin\semver" %*
|
||||
28
node_modules/.bin/semver.ps1
generated
vendored
Normal file
28
node_modules/.bin/semver.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../semver/bin/semver" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../semver/bin/semver" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../semver/bin/semver" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../semver/bin/semver" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/terser
generated
vendored
Normal file
16
node_modules/.bin/terser
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../terser/bin/terser" "$@"
|
||||
else
|
||||
exec node "$basedir/../terser/bin/terser" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/terser.cmd
generated
vendored
Normal file
17
node_modules/.bin/terser.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\terser\bin\terser" %*
|
||||
28
node_modules/.bin/terser.ps1
generated
vendored
Normal file
28
node_modules/.bin/terser.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../terser/bin/terser" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../terser/bin/terser" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../terser/bin/terser" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../terser/bin/terser" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
16
node_modules/.bin/vite
generated
vendored
Normal file
16
node_modules/.bin/vite
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/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/../vite/bin/vite.js" "$@"
|
||||
else
|
||||
exec node "$basedir/../vite/bin/vite.js" "$@"
|
||||
fi
|
||||
17
node_modules/.bin/vite.cmd
generated
vendored
Normal file
17
node_modules/.bin/vite.cmd
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
@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%\..\vite\bin\vite.js" %*
|
||||
28
node_modules/.bin/vite.ps1
generated
vendored
Normal file
28
node_modules/.bin/vite.ps1
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/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/../vite/bin/vite.js" $args
|
||||
} else {
|
||||
& "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
} else {
|
||||
# Support pipeline input
|
||||
if ($MyInvocation.ExpectingInput) {
|
||||
$input | & "node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
} else {
|
||||
& "node$exe" "$basedir/../vite/bin/vite.js" $args
|
||||
}
|
||||
$ret=$LASTEXITCODE
|
||||
}
|
||||
exit $ret
|
||||
932
node_modules/.package-lock.json
generated
vendored
Normal file
932
node_modules/.package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,932 @@
|
||||
{
|
||||
"name": "pandona-engine",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
|
||||
"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
|
||||
"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
|
||||
"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
|
||||
"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
|
||||
"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
|
||||
"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
|
||||
"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
|
||||
"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
|
||||
"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
|
||||
"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
|
||||
"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
|
||||
"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
|
||||
"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
|
||||
"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
|
||||
"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/gen-mapping": {
|
||||
"version": "0.3.13",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
|
||||
"integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/resolve-uri": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/source-map": {
|
||||
"version": "0.3.11",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
|
||||
"integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.5",
|
||||
"@jridgewell/trace-mapping": "^0.3.25"
|
||||
}
|
||||
},
|
||||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
|
||||
"integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.31",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
|
||||
"integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.15.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "2.20.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/copy-anything": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
|
||||
"integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-what": "^3.14.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/mesqueeb"
|
||||
}
|
||||
},
|
||||
"node_modules/dotenv": {
|
||||
"version": "17.2.3",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
|
||||
"integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://dotenvx.com"
|
||||
}
|
||||
},
|
||||
"node_modules/errno": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||
"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"prr": "~1.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"errno": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.18.20",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
|
||||
"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/android-arm": "0.18.20",
|
||||
"@esbuild/android-arm64": "0.18.20",
|
||||
"@esbuild/android-x64": "0.18.20",
|
||||
"@esbuild/darwin-arm64": "0.18.20",
|
||||
"@esbuild/darwin-x64": "0.18.20",
|
||||
"@esbuild/freebsd-arm64": "0.18.20",
|
||||
"@esbuild/freebsd-x64": "0.18.20",
|
||||
"@esbuild/linux-arm": "0.18.20",
|
||||
"@esbuild/linux-arm64": "0.18.20",
|
||||
"@esbuild/linux-ia32": "0.18.20",
|
||||
"@esbuild/linux-loong64": "0.18.20",
|
||||
"@esbuild/linux-mips64el": "0.18.20",
|
||||
"@esbuild/linux-ppc64": "0.18.20",
|
||||
"@esbuild/linux-riscv64": "0.18.20",
|
||||
"@esbuild/linux-s390x": "0.18.20",
|
||||
"@esbuild/linux-x64": "0.18.20",
|
||||
"@esbuild/netbsd-x64": "0.18.20",
|
||||
"@esbuild/openbsd-x64": "0.18.20",
|
||||
"@esbuild/sunos-x64": "0.18.20",
|
||||
"@esbuild/win32-arm64": "0.18.20",
|
||||
"@esbuild/win32-ia32": "0.18.20",
|
||||
"@esbuild/win32-x64": "0.18.20"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"ideallyInert": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/graceful-fs": {
|
||||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "0.5.5",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
|
||||
"integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"image-size": "bin/image-size.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-what": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
|
||||
"integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/less": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/less/-/less-4.4.1.tgz",
|
||||
"integrity": "sha512-X9HKyiXPi0f/ed0XhgUlBeFfxrlDP3xR4M7768Zl+WXLUViuL9AOPPJP4nCV0tgRWvTYvpNmN0SFhZOQzy16PA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"copy-anything": "^2.0.1",
|
||||
"parse-node-version": "^1.0.1",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"bin": {
|
||||
"lessc": "bin/lessc"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"errno": "^0.1.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"image-size": "~0.5.0",
|
||||
"make-dir": "^2.1.0",
|
||||
"mime": "^1.4.1",
|
||||
"needle": "^3.1.0",
|
||||
"source-map": "~0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
|
||||
"integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"pify": "^4.0.1",
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/needle": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/needle/-/needle-3.3.1.tgz",
|
||||
"integrity": "sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.3",
|
||||
"sax": "^1.2.4"
|
||||
},
|
||||
"bin": {
|
||||
"needle": "bin/needle"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-node-version": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
|
||||
"integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"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": "ISC"
|
||||
},
|
||||
"node_modules/pify": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
|
||||
"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "3.29.5",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz",
|
||||
"integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.18.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "5.7.2",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
|
||||
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-support": {
|
||||
"version": "0.5.21",
|
||||
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
|
||||
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"source-map": "^0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.44.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz",
|
||||
"integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
"acorn": "^8.15.0",
|
||||
"commander": "^2.20.0",
|
||||
"source-map-support": "~0.5.20"
|
||||
},
|
||||
"bin": {
|
||||
"terser": "bin/terser"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "4.5.14",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz",
|
||||
"integrity": "sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.18.10",
|
||||
"postcss": "^8.4.27",
|
||||
"rollup": "^3.27.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">= 14",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_010fc2f4/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_010fc2f4/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_18b76d8e/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_18b76d8e/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_2e8f7c60/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_2e8f7c60/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_395e6c76/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_395e6c76/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_5ae8cc47/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_5ae8cc47/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_6ce8b2a3/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_6ce8b2a3/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_747eaad1/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_747eaad1/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_83a3f12a/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_83a3f12a/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_95c788c0/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_95c788c0/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_db29f874/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_db29f874/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_eea5b4f0/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_eea5b4f0/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_f0bd8d06/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_f0bd8d06/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/.vite/deps_temp_f4e5b100/package.json
generated
vendored
Normal file
3
node_modules/.vite/deps_temp_f4e5b100/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
3
node_modules/@esbuild/win32-x64/README.md
generated
vendored
Normal file
3
node_modules/@esbuild/win32-x64/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# esbuild
|
||||
|
||||
This is the Windows 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
|
||||
BIN
node_modules/@esbuild/win32-x64/esbuild.exe
generated
vendored
Normal file
BIN
node_modules/@esbuild/win32-x64/esbuild.exe
generated
vendored
Normal file
Binary file not shown.
17
node_modules/@esbuild/win32-x64/package.json
generated
vendored
Normal file
17
node_modules/@esbuild/win32-x64/package.json
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@esbuild/win32-x64",
|
||||
"version": "0.18.20",
|
||||
"description": "The Windows 64-bit binary for esbuild, a JavaScript bundler.",
|
||||
"repository": "https://github.com/evanw/esbuild",
|
||||
"license": "MIT",
|
||||
"preferUnplugged": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"cpu": [
|
||||
"x64"
|
||||
]
|
||||
}
|
||||
19
node_modules/@jridgewell/gen-mapping/LICENSE
generated
vendored
Normal file
19
node_modules/@jridgewell/gen-mapping/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright 2024 Justin Ridgewell <justin@ridgewell.name>
|
||||
|
||||
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.
|
||||
227
node_modules/@jridgewell/gen-mapping/README.md
generated
vendored
Normal file
227
node_modules/@jridgewell/gen-mapping/README.md
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
# @jridgewell/gen-mapping
|
||||
|
||||
> Generate source maps
|
||||
|
||||
`gen-mapping` allows you to generate a source map during transpilation or minification.
|
||||
With a source map, you're able to trace the original location in the source file, either in Chrome's
|
||||
DevTools or using a library like [`@jridgewell/trace-mapping`][trace-mapping].
|
||||
|
||||
You may already be familiar with the [`source-map`][source-map] package's `SourceMapGenerator`. This
|
||||
provides the same `addMapping` and `setSourceContent` API.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install @jridgewell/gen-mapping
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```typescript
|
||||
import { GenMapping, addMapping, setSourceContent, toEncodedMap, toDecodedMap } from '@jridgewell/gen-mapping';
|
||||
|
||||
const map = new GenMapping({
|
||||
file: 'output.js',
|
||||
sourceRoot: 'https://example.com/',
|
||||
});
|
||||
|
||||
setSourceContent(map, 'input.js', `function foo() {}`);
|
||||
|
||||
addMapping(map, {
|
||||
// Lines start at line 1, columns at column 0.
|
||||
generated: { line: 1, column: 0 },
|
||||
source: 'input.js',
|
||||
original: { line: 1, column: 0 },
|
||||
});
|
||||
|
||||
addMapping(map, {
|
||||
generated: { line: 1, column: 9 },
|
||||
source: 'input.js',
|
||||
original: { line: 1, column: 9 },
|
||||
name: 'foo',
|
||||
});
|
||||
|
||||
assert.deepEqual(toDecodedMap(map), {
|
||||
version: 3,
|
||||
file: 'output.js',
|
||||
names: ['foo'],
|
||||
sourceRoot: 'https://example.com/',
|
||||
sources: ['input.js'],
|
||||
sourcesContent: ['function foo() {}'],
|
||||
mappings: [
|
||||
[ [0, 0, 0, 0], [9, 0, 0, 9, 0] ]
|
||||
],
|
||||
});
|
||||
|
||||
assert.deepEqual(toEncodedMap(map), {
|
||||
version: 3,
|
||||
file: 'output.js',
|
||||
names: ['foo'],
|
||||
sourceRoot: 'https://example.com/',
|
||||
sources: ['input.js'],
|
||||
sourcesContent: ['function foo() {}'],
|
||||
mappings: 'AAAA,SAASA',
|
||||
});
|
||||
```
|
||||
|
||||
### Smaller Sourcemaps
|
||||
|
||||
Not everything needs to be added to a sourcemap, and needless markings can cause signficantly
|
||||
larger file sizes. `gen-mapping` exposes `maybeAddSegment`/`maybeAddMapping` APIs that will
|
||||
intelligently determine if this marking adds useful information. If not, the marking will be
|
||||
skipped.
|
||||
|
||||
```typescript
|
||||
import { maybeAddMapping } from '@jridgewell/gen-mapping';
|
||||
|
||||
const map = new GenMapping();
|
||||
|
||||
// Adding a sourceless marking at the beginning of a line isn't useful.
|
||||
maybeAddMapping(map, {
|
||||
generated: { line: 1, column: 0 },
|
||||
});
|
||||
|
||||
// Adding a new source marking is useful.
|
||||
maybeAddMapping(map, {
|
||||
generated: { line: 1, column: 0 },
|
||||
source: 'input.js',
|
||||
original: { line: 1, column: 0 },
|
||||
});
|
||||
|
||||
// But adding another marking pointing to the exact same original location isn't, even if the
|
||||
// generated column changed.
|
||||
maybeAddMapping(map, {
|
||||
generated: { line: 1, column: 9 },
|
||||
source: 'input.js',
|
||||
original: { line: 1, column: 0 },
|
||||
});
|
||||
|
||||
assert.deepEqual(toEncodedMap(map), {
|
||||
version: 3,
|
||||
names: [],
|
||||
sources: ['input.js'],
|
||||
sourcesContent: [null],
|
||||
mappings: 'AAAA',
|
||||
});
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
```
|
||||
node v18.0.0
|
||||
|
||||
amp.js.map
|
||||
Memory Usage:
|
||||
gen-mapping: addSegment 5852872 bytes
|
||||
gen-mapping: addMapping 7716042 bytes
|
||||
source-map-js 6143250 bytes
|
||||
source-map-0.6.1 6124102 bytes
|
||||
source-map-0.8.0 6121173 bytes
|
||||
Smallest memory usage is gen-mapping: addSegment
|
||||
|
||||
Adding speed:
|
||||
gen-mapping: addSegment x 441 ops/sec ±2.07% (90 runs sampled)
|
||||
gen-mapping: addMapping x 350 ops/sec ±2.40% (86 runs sampled)
|
||||
source-map-js: addMapping x 169 ops/sec ±2.42% (80 runs sampled)
|
||||
source-map-0.6.1: addMapping x 167 ops/sec ±2.56% (80 runs sampled)
|
||||
source-map-0.8.0: addMapping x 168 ops/sec ±2.52% (80 runs sampled)
|
||||
Fastest is gen-mapping: addSegment
|
||||
|
||||
Generate speed:
|
||||
gen-mapping: decoded output x 150,824,370 ops/sec ±0.07% (102 runs sampled)
|
||||
gen-mapping: encoded output x 663 ops/sec ±0.22% (98 runs sampled)
|
||||
source-map-js: encoded output x 197 ops/sec ±0.45% (84 runs sampled)
|
||||
source-map-0.6.1: encoded output x 198 ops/sec ±0.33% (85 runs sampled)
|
||||
source-map-0.8.0: encoded output x 197 ops/sec ±0.06% (93 runs sampled)
|
||||
Fastest is gen-mapping: decoded output
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
babel.min.js.map
|
||||
Memory Usage:
|
||||
gen-mapping: addSegment 37578063 bytes
|
||||
gen-mapping: addMapping 37212897 bytes
|
||||
source-map-js 47638527 bytes
|
||||
source-map-0.6.1 47690503 bytes
|
||||
source-map-0.8.0 47470188 bytes
|
||||
Smallest memory usage is gen-mapping: addMapping
|
||||
|
||||
Adding speed:
|
||||
gen-mapping: addSegment x 31.05 ops/sec ±8.31% (43 runs sampled)
|
||||
gen-mapping: addMapping x 29.83 ops/sec ±7.36% (51 runs sampled)
|
||||
source-map-js: addMapping x 20.73 ops/sec ±6.22% (38 runs sampled)
|
||||
source-map-0.6.1: addMapping x 20.03 ops/sec ±10.51% (38 runs sampled)
|
||||
source-map-0.8.0: addMapping x 19.30 ops/sec ±8.27% (37 runs sampled)
|
||||
Fastest is gen-mapping: addSegment
|
||||
|
||||
Generate speed:
|
||||
gen-mapping: decoded output x 381,379,234 ops/sec ±0.29% (96 runs sampled)
|
||||
gen-mapping: encoded output x 95.15 ops/sec ±2.98% (72 runs sampled)
|
||||
source-map-js: encoded output x 15.20 ops/sec ±7.41% (33 runs sampled)
|
||||
source-map-0.6.1: encoded output x 16.36 ops/sec ±10.46% (31 runs sampled)
|
||||
source-map-0.8.0: encoded output x 16.06 ops/sec ±6.45% (31 runs sampled)
|
||||
Fastest is gen-mapping: decoded output
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
preact.js.map
|
||||
Memory Usage:
|
||||
gen-mapping: addSegment 416247 bytes
|
||||
gen-mapping: addMapping 419824 bytes
|
||||
source-map-js 1024619 bytes
|
||||
source-map-0.6.1 1146004 bytes
|
||||
source-map-0.8.0 1113250 bytes
|
||||
Smallest memory usage is gen-mapping: addSegment
|
||||
|
||||
Adding speed:
|
||||
gen-mapping: addSegment x 13,755 ops/sec ±0.15% (98 runs sampled)
|
||||
gen-mapping: addMapping x 13,013 ops/sec ±0.11% (101 runs sampled)
|
||||
source-map-js: addMapping x 4,564 ops/sec ±0.21% (98 runs sampled)
|
||||
source-map-0.6.1: addMapping x 4,562 ops/sec ±0.11% (99 runs sampled)
|
||||
source-map-0.8.0: addMapping x 4,593 ops/sec ±0.11% (100 runs sampled)
|
||||
Fastest is gen-mapping: addSegment
|
||||
|
||||
Generate speed:
|
||||
gen-mapping: decoded output x 379,864,020 ops/sec ±0.23% (93 runs sampled)
|
||||
gen-mapping: encoded output x 14,368 ops/sec ±4.07% (82 runs sampled)
|
||||
source-map-js: encoded output x 5,261 ops/sec ±0.21% (99 runs sampled)
|
||||
source-map-0.6.1: encoded output x 5,124 ops/sec ±0.58% (99 runs sampled)
|
||||
source-map-0.8.0: encoded output x 5,434 ops/sec ±0.33% (96 runs sampled)
|
||||
Fastest is gen-mapping: decoded output
|
||||
|
||||
|
||||
***
|
||||
|
||||
|
||||
react.js.map
|
||||
Memory Usage:
|
||||
gen-mapping: addSegment 975096 bytes
|
||||
gen-mapping: addMapping 1102981 bytes
|
||||
source-map-js 2918836 bytes
|
||||
source-map-0.6.1 2885435 bytes
|
||||
source-map-0.8.0 2874336 bytes
|
||||
Smallest memory usage is gen-mapping: addSegment
|
||||
|
||||
Adding speed:
|
||||
gen-mapping: addSegment x 4,772 ops/sec ±0.15% (100 runs sampled)
|
||||
gen-mapping: addMapping x 4,456 ops/sec ±0.13% (97 runs sampled)
|
||||
source-map-js: addMapping x 1,618 ops/sec ±0.24% (97 runs sampled)
|
||||
source-map-0.6.1: addMapping x 1,622 ops/sec ±0.12% (99 runs sampled)
|
||||
source-map-0.8.0: addMapping x 1,631 ops/sec ±0.12% (100 runs sampled)
|
||||
Fastest is gen-mapping: addSegment
|
||||
|
||||
Generate speed:
|
||||
gen-mapping: decoded output x 379,107,695 ops/sec ±0.07% (99 runs sampled)
|
||||
gen-mapping: encoded output x 5,421 ops/sec ±1.60% (89 runs sampled)
|
||||
source-map-js: encoded output x 2,113 ops/sec ±1.81% (98 runs sampled)
|
||||
source-map-0.6.1: encoded output x 2,126 ops/sec ±0.10% (100 runs sampled)
|
||||
source-map-0.8.0: encoded output x 2,176 ops/sec ±0.39% (98 runs sampled)
|
||||
Fastest is gen-mapping: decoded output
|
||||
```
|
||||
|
||||
[source-map]: https://www.npmjs.com/package/source-map
|
||||
[trace-mapping]: https://github.com/jridgewell/sourcemaps/tree/main/packages/trace-mapping
|
||||
292
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.mjs
generated
vendored
Normal file
292
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.mjs
generated
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
// src/set-array.ts
|
||||
var SetArray = class {
|
||||
constructor() {
|
||||
this._indexes = { __proto__: null };
|
||||
this.array = [];
|
||||
}
|
||||
};
|
||||
function cast(set) {
|
||||
return set;
|
||||
}
|
||||
function get(setarr, key) {
|
||||
return cast(setarr)._indexes[key];
|
||||
}
|
||||
function put(setarr, key) {
|
||||
const index = get(setarr, key);
|
||||
if (index !== void 0) return index;
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
const length = array.push(key);
|
||||
return indexes[key] = length - 1;
|
||||
}
|
||||
function remove(setarr, key) {
|
||||
const index = get(setarr, key);
|
||||
if (index === void 0) return;
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
for (let i = index + 1; i < array.length; i++) {
|
||||
const k = array[i];
|
||||
array[i - 1] = k;
|
||||
indexes[k]--;
|
||||
}
|
||||
indexes[key] = void 0;
|
||||
array.pop();
|
||||
}
|
||||
|
||||
// src/gen-mapping.ts
|
||||
import {
|
||||
encode
|
||||
} from "@jridgewell/sourcemap-codec";
|
||||
import { TraceMap, decodedMappings } from "@jridgewell/trace-mapping";
|
||||
|
||||
// src/sourcemap-segment.ts
|
||||
var COLUMN = 0;
|
||||
var SOURCES_INDEX = 1;
|
||||
var SOURCE_LINE = 2;
|
||||
var SOURCE_COLUMN = 3;
|
||||
var NAMES_INDEX = 4;
|
||||
|
||||
// src/gen-mapping.ts
|
||||
var NO_NAME = -1;
|
||||
var GenMapping = class {
|
||||
constructor({ file, sourceRoot } = {}) {
|
||||
this._names = new SetArray();
|
||||
this._sources = new SetArray();
|
||||
this._sourcesContent = [];
|
||||
this._mappings = [];
|
||||
this.file = file;
|
||||
this.sourceRoot = sourceRoot;
|
||||
this._ignoreList = new SetArray();
|
||||
}
|
||||
};
|
||||
function cast2(map) {
|
||||
return map;
|
||||
}
|
||||
function addSegment(map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) {
|
||||
return addSegmentInternal(
|
||||
false,
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content
|
||||
);
|
||||
}
|
||||
function addMapping(map, mapping) {
|
||||
return addMappingInternal(false, map, mapping);
|
||||
}
|
||||
var maybeAddSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) => {
|
||||
return addSegmentInternal(
|
||||
true,
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content
|
||||
);
|
||||
};
|
||||
var maybeAddMapping = (map, mapping) => {
|
||||
return addMappingInternal(true, map, mapping);
|
||||
};
|
||||
function setSourceContent(map, source, content) {
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast2(map);
|
||||
const index = put(sources, source);
|
||||
sourcesContent[index] = content;
|
||||
}
|
||||
function setIgnore(map, source, ignore = true) {
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_ignoreList: ignoreList
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast2(map);
|
||||
const index = put(sources, source);
|
||||
if (index === sourcesContent.length) sourcesContent[index] = null;
|
||||
if (ignore) put(ignoreList, index);
|
||||
else remove(ignoreList, index);
|
||||
}
|
||||
function toDecodedMap(map) {
|
||||
const {
|
||||
_mappings: mappings,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_names: names,
|
||||
_ignoreList: ignoreList
|
||||
// _originalScopes: originalScopes,
|
||||
// _generatedRanges: generatedRanges,
|
||||
} = cast2(map);
|
||||
removeEmptyFinalLines(mappings);
|
||||
return {
|
||||
version: 3,
|
||||
file: map.file || void 0,
|
||||
names: names.array,
|
||||
sourceRoot: map.sourceRoot || void 0,
|
||||
sources: sources.array,
|
||||
sourcesContent,
|
||||
mappings,
|
||||
// originalScopes,
|
||||
// generatedRanges,
|
||||
ignoreList: ignoreList.array
|
||||
};
|
||||
}
|
||||
function toEncodedMap(map) {
|
||||
const decoded = toDecodedMap(map);
|
||||
return Object.assign({}, decoded, {
|
||||
// originalScopes: decoded.originalScopes.map((os) => encodeOriginalScopes(os)),
|
||||
// generatedRanges: encodeGeneratedRanges(decoded.generatedRanges as GeneratedRange[]),
|
||||
mappings: encode(decoded.mappings)
|
||||
});
|
||||
}
|
||||
function fromMap(input) {
|
||||
const map = new TraceMap(input);
|
||||
const gen = new GenMapping({ file: map.file, sourceRoot: map.sourceRoot });
|
||||
putAll(cast2(gen)._names, map.names);
|
||||
putAll(cast2(gen)._sources, map.sources);
|
||||
cast2(gen)._sourcesContent = map.sourcesContent || map.sources.map(() => null);
|
||||
cast2(gen)._mappings = decodedMappings(map);
|
||||
if (map.ignoreList) putAll(cast2(gen)._ignoreList, map.ignoreList);
|
||||
return gen;
|
||||
}
|
||||
function allMappings(map) {
|
||||
const out = [];
|
||||
const { _mappings: mappings, _sources: sources, _names: names } = cast2(map);
|
||||
for (let i = 0; i < mappings.length; i++) {
|
||||
const line = mappings[i];
|
||||
for (let j = 0; j < line.length; j++) {
|
||||
const seg = line[j];
|
||||
const generated = { line: i + 1, column: seg[COLUMN] };
|
||||
let source = void 0;
|
||||
let original = void 0;
|
||||
let name = void 0;
|
||||
if (seg.length !== 1) {
|
||||
source = sources.array[seg[SOURCES_INDEX]];
|
||||
original = { line: seg[SOURCE_LINE] + 1, column: seg[SOURCE_COLUMN] };
|
||||
if (seg.length === 5) name = names.array[seg[NAMES_INDEX]];
|
||||
}
|
||||
out.push({ generated, source, original, name });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function addSegmentInternal(skipable, map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) {
|
||||
const {
|
||||
_mappings: mappings,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_names: names
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast2(map);
|
||||
const line = getIndex(mappings, genLine);
|
||||
const index = getColumnIndex(line, genColumn);
|
||||
if (!source) {
|
||||
if (skipable && skipSourceless(line, index)) return;
|
||||
return insert(line, index, [genColumn]);
|
||||
}
|
||||
assert(sourceLine);
|
||||
assert(sourceColumn);
|
||||
const sourcesIndex = put(sources, source);
|
||||
const namesIndex = name ? put(names, name) : NO_NAME;
|
||||
if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content != null ? content : null;
|
||||
if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) {
|
||||
return;
|
||||
}
|
||||
return insert(
|
||||
line,
|
||||
index,
|
||||
name ? [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex] : [genColumn, sourcesIndex, sourceLine, sourceColumn]
|
||||
);
|
||||
}
|
||||
function assert(_val) {
|
||||
}
|
||||
function getIndex(arr, index) {
|
||||
for (let i = arr.length; i <= index; i++) {
|
||||
arr[i] = [];
|
||||
}
|
||||
return arr[index];
|
||||
}
|
||||
function getColumnIndex(line, genColumn) {
|
||||
let index = line.length;
|
||||
for (let i = index - 1; i >= 0; index = i--) {
|
||||
const current = line[i];
|
||||
if (genColumn >= current[COLUMN]) break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
function insert(array, index, value) {
|
||||
for (let i = array.length; i > index; i--) {
|
||||
array[i] = array[i - 1];
|
||||
}
|
||||
array[index] = value;
|
||||
}
|
||||
function removeEmptyFinalLines(mappings) {
|
||||
const { length } = mappings;
|
||||
let len = length;
|
||||
for (let i = len - 1; i >= 0; len = i, i--) {
|
||||
if (mappings[i].length > 0) break;
|
||||
}
|
||||
if (len < length) mappings.length = len;
|
||||
}
|
||||
function putAll(setarr, array) {
|
||||
for (let i = 0; i < array.length; i++) put(setarr, array[i]);
|
||||
}
|
||||
function skipSourceless(line, index) {
|
||||
if (index === 0) return true;
|
||||
const prev = line[index - 1];
|
||||
return prev.length === 1;
|
||||
}
|
||||
function skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex) {
|
||||
if (index === 0) return false;
|
||||
const prev = line[index - 1];
|
||||
if (prev.length === 1) return false;
|
||||
return sourcesIndex === prev[SOURCES_INDEX] && sourceLine === prev[SOURCE_LINE] && sourceColumn === prev[SOURCE_COLUMN] && namesIndex === (prev.length === 5 ? prev[NAMES_INDEX] : NO_NAME);
|
||||
}
|
||||
function addMappingInternal(skipable, map, mapping) {
|
||||
const { generated, source, original, name, content } = mapping;
|
||||
if (!source) {
|
||||
return addSegmentInternal(
|
||||
skipable,
|
||||
map,
|
||||
generated.line - 1,
|
||||
generated.column,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
assert(original);
|
||||
return addSegmentInternal(
|
||||
skipable,
|
||||
map,
|
||||
generated.line - 1,
|
||||
generated.column,
|
||||
source,
|
||||
original.line - 1,
|
||||
original.column,
|
||||
name,
|
||||
content
|
||||
);
|
||||
}
|
||||
export {
|
||||
GenMapping,
|
||||
addMapping,
|
||||
addSegment,
|
||||
allMappings,
|
||||
fromMap,
|
||||
maybeAddMapping,
|
||||
maybeAddSegment,
|
||||
setIgnore,
|
||||
setSourceContent,
|
||||
toDecodedMap,
|
||||
toEncodedMap
|
||||
};
|
||||
//# sourceMappingURL=gen-mapping.mjs.map
|
||||
6
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.mjs.map
generated
vendored
Normal file
6
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
358
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js
generated
vendored
Normal file
358
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js
generated
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
(function (global, factory) {
|
||||
if (typeof exports === 'object' && typeof module !== 'undefined') {
|
||||
factory(module, require('@jridgewell/sourcemap-codec'), require('@jridgewell/trace-mapping'));
|
||||
module.exports = def(module);
|
||||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(['module', '@jridgewell/sourcemap-codec', '@jridgewell/trace-mapping'], function(mod) {
|
||||
factory.apply(this, arguments);
|
||||
mod.exports = def(mod);
|
||||
});
|
||||
} else {
|
||||
const mod = { exports: {} };
|
||||
factory(mod, global.sourcemapCodec, global.traceMapping);
|
||||
global = typeof globalThis !== 'undefined' ? globalThis : global || self;
|
||||
global.genMapping = def(mod);
|
||||
}
|
||||
function def(m) { return 'default' in m.exports ? m.exports.default : m.exports; }
|
||||
})(this, (function (module, require_sourcemapCodec, require_traceMapping) {
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __commonJS = (cb, mod) => function __require() {
|
||||
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
||||
};
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// umd:@jridgewell/sourcemap-codec
|
||||
var require_sourcemap_codec = __commonJS({
|
||||
"umd:@jridgewell/sourcemap-codec"(exports, module2) {
|
||||
module2.exports = require_sourcemapCodec;
|
||||
}
|
||||
});
|
||||
|
||||
// umd:@jridgewell/trace-mapping
|
||||
var require_trace_mapping = __commonJS({
|
||||
"umd:@jridgewell/trace-mapping"(exports, module2) {
|
||||
module2.exports = require_traceMapping;
|
||||
}
|
||||
});
|
||||
|
||||
// src/gen-mapping.ts
|
||||
var gen_mapping_exports = {};
|
||||
__export(gen_mapping_exports, {
|
||||
GenMapping: () => GenMapping,
|
||||
addMapping: () => addMapping,
|
||||
addSegment: () => addSegment,
|
||||
allMappings: () => allMappings,
|
||||
fromMap: () => fromMap,
|
||||
maybeAddMapping: () => maybeAddMapping,
|
||||
maybeAddSegment: () => maybeAddSegment,
|
||||
setIgnore: () => setIgnore,
|
||||
setSourceContent: () => setSourceContent,
|
||||
toDecodedMap: () => toDecodedMap,
|
||||
toEncodedMap: () => toEncodedMap
|
||||
});
|
||||
module.exports = __toCommonJS(gen_mapping_exports);
|
||||
|
||||
// src/set-array.ts
|
||||
var SetArray = class {
|
||||
constructor() {
|
||||
this._indexes = { __proto__: null };
|
||||
this.array = [];
|
||||
}
|
||||
};
|
||||
function cast(set) {
|
||||
return set;
|
||||
}
|
||||
function get(setarr, key) {
|
||||
return cast(setarr)._indexes[key];
|
||||
}
|
||||
function put(setarr, key) {
|
||||
const index = get(setarr, key);
|
||||
if (index !== void 0) return index;
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
const length = array.push(key);
|
||||
return indexes[key] = length - 1;
|
||||
}
|
||||
function remove(setarr, key) {
|
||||
const index = get(setarr, key);
|
||||
if (index === void 0) return;
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
for (let i = index + 1; i < array.length; i++) {
|
||||
const k = array[i];
|
||||
array[i - 1] = k;
|
||||
indexes[k]--;
|
||||
}
|
||||
indexes[key] = void 0;
|
||||
array.pop();
|
||||
}
|
||||
|
||||
// src/gen-mapping.ts
|
||||
var import_sourcemap_codec = __toESM(require_sourcemap_codec());
|
||||
var import_trace_mapping = __toESM(require_trace_mapping());
|
||||
|
||||
// src/sourcemap-segment.ts
|
||||
var COLUMN = 0;
|
||||
var SOURCES_INDEX = 1;
|
||||
var SOURCE_LINE = 2;
|
||||
var SOURCE_COLUMN = 3;
|
||||
var NAMES_INDEX = 4;
|
||||
|
||||
// src/gen-mapping.ts
|
||||
var NO_NAME = -1;
|
||||
var GenMapping = class {
|
||||
constructor({ file, sourceRoot } = {}) {
|
||||
this._names = new SetArray();
|
||||
this._sources = new SetArray();
|
||||
this._sourcesContent = [];
|
||||
this._mappings = [];
|
||||
this.file = file;
|
||||
this.sourceRoot = sourceRoot;
|
||||
this._ignoreList = new SetArray();
|
||||
}
|
||||
};
|
||||
function cast2(map) {
|
||||
return map;
|
||||
}
|
||||
function addSegment(map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) {
|
||||
return addSegmentInternal(
|
||||
false,
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content
|
||||
);
|
||||
}
|
||||
function addMapping(map, mapping) {
|
||||
return addMappingInternal(false, map, mapping);
|
||||
}
|
||||
var maybeAddSegment = (map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) => {
|
||||
return addSegmentInternal(
|
||||
true,
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content
|
||||
);
|
||||
};
|
||||
var maybeAddMapping = (map, mapping) => {
|
||||
return addMappingInternal(true, map, mapping);
|
||||
};
|
||||
function setSourceContent(map, source, content) {
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast2(map);
|
||||
const index = put(sources, source);
|
||||
sourcesContent[index] = content;
|
||||
}
|
||||
function setIgnore(map, source, ignore = true) {
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_ignoreList: ignoreList
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast2(map);
|
||||
const index = put(sources, source);
|
||||
if (index === sourcesContent.length) sourcesContent[index] = null;
|
||||
if (ignore) put(ignoreList, index);
|
||||
else remove(ignoreList, index);
|
||||
}
|
||||
function toDecodedMap(map) {
|
||||
const {
|
||||
_mappings: mappings,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_names: names,
|
||||
_ignoreList: ignoreList
|
||||
// _originalScopes: originalScopes,
|
||||
// _generatedRanges: generatedRanges,
|
||||
} = cast2(map);
|
||||
removeEmptyFinalLines(mappings);
|
||||
return {
|
||||
version: 3,
|
||||
file: map.file || void 0,
|
||||
names: names.array,
|
||||
sourceRoot: map.sourceRoot || void 0,
|
||||
sources: sources.array,
|
||||
sourcesContent,
|
||||
mappings,
|
||||
// originalScopes,
|
||||
// generatedRanges,
|
||||
ignoreList: ignoreList.array
|
||||
};
|
||||
}
|
||||
function toEncodedMap(map) {
|
||||
const decoded = toDecodedMap(map);
|
||||
return Object.assign({}, decoded, {
|
||||
// originalScopes: decoded.originalScopes.map((os) => encodeOriginalScopes(os)),
|
||||
// generatedRanges: encodeGeneratedRanges(decoded.generatedRanges as GeneratedRange[]),
|
||||
mappings: (0, import_sourcemap_codec.encode)(decoded.mappings)
|
||||
});
|
||||
}
|
||||
function fromMap(input) {
|
||||
const map = new import_trace_mapping.TraceMap(input);
|
||||
const gen = new GenMapping({ file: map.file, sourceRoot: map.sourceRoot });
|
||||
putAll(cast2(gen)._names, map.names);
|
||||
putAll(cast2(gen)._sources, map.sources);
|
||||
cast2(gen)._sourcesContent = map.sourcesContent || map.sources.map(() => null);
|
||||
cast2(gen)._mappings = (0, import_trace_mapping.decodedMappings)(map);
|
||||
if (map.ignoreList) putAll(cast2(gen)._ignoreList, map.ignoreList);
|
||||
return gen;
|
||||
}
|
||||
function allMappings(map) {
|
||||
const out = [];
|
||||
const { _mappings: mappings, _sources: sources, _names: names } = cast2(map);
|
||||
for (let i = 0; i < mappings.length; i++) {
|
||||
const line = mappings[i];
|
||||
for (let j = 0; j < line.length; j++) {
|
||||
const seg = line[j];
|
||||
const generated = { line: i + 1, column: seg[COLUMN] };
|
||||
let source = void 0;
|
||||
let original = void 0;
|
||||
let name = void 0;
|
||||
if (seg.length !== 1) {
|
||||
source = sources.array[seg[SOURCES_INDEX]];
|
||||
original = { line: seg[SOURCE_LINE] + 1, column: seg[SOURCE_COLUMN] };
|
||||
if (seg.length === 5) name = names.array[seg[NAMES_INDEX]];
|
||||
}
|
||||
out.push({ generated, source, original, name });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function addSegmentInternal(skipable, map, genLine, genColumn, source, sourceLine, sourceColumn, name, content) {
|
||||
const {
|
||||
_mappings: mappings,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_names: names
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast2(map);
|
||||
const line = getIndex(mappings, genLine);
|
||||
const index = getColumnIndex(line, genColumn);
|
||||
if (!source) {
|
||||
if (skipable && skipSourceless(line, index)) return;
|
||||
return insert(line, index, [genColumn]);
|
||||
}
|
||||
assert(sourceLine);
|
||||
assert(sourceColumn);
|
||||
const sourcesIndex = put(sources, source);
|
||||
const namesIndex = name ? put(names, name) : NO_NAME;
|
||||
if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content != null ? content : null;
|
||||
if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) {
|
||||
return;
|
||||
}
|
||||
return insert(
|
||||
line,
|
||||
index,
|
||||
name ? [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex] : [genColumn, sourcesIndex, sourceLine, sourceColumn]
|
||||
);
|
||||
}
|
||||
function assert(_val) {
|
||||
}
|
||||
function getIndex(arr, index) {
|
||||
for (let i = arr.length; i <= index; i++) {
|
||||
arr[i] = [];
|
||||
}
|
||||
return arr[index];
|
||||
}
|
||||
function getColumnIndex(line, genColumn) {
|
||||
let index = line.length;
|
||||
for (let i = index - 1; i >= 0; index = i--) {
|
||||
const current = line[i];
|
||||
if (genColumn >= current[COLUMN]) break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
function insert(array, index, value) {
|
||||
for (let i = array.length; i > index; i--) {
|
||||
array[i] = array[i - 1];
|
||||
}
|
||||
array[index] = value;
|
||||
}
|
||||
function removeEmptyFinalLines(mappings) {
|
||||
const { length } = mappings;
|
||||
let len = length;
|
||||
for (let i = len - 1; i >= 0; len = i, i--) {
|
||||
if (mappings[i].length > 0) break;
|
||||
}
|
||||
if (len < length) mappings.length = len;
|
||||
}
|
||||
function putAll(setarr, array) {
|
||||
for (let i = 0; i < array.length; i++) put(setarr, array[i]);
|
||||
}
|
||||
function skipSourceless(line, index) {
|
||||
if (index === 0) return true;
|
||||
const prev = line[index - 1];
|
||||
return prev.length === 1;
|
||||
}
|
||||
function skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex) {
|
||||
if (index === 0) return false;
|
||||
const prev = line[index - 1];
|
||||
if (prev.length === 1) return false;
|
||||
return sourcesIndex === prev[SOURCES_INDEX] && sourceLine === prev[SOURCE_LINE] && sourceColumn === prev[SOURCE_COLUMN] && namesIndex === (prev.length === 5 ? prev[NAMES_INDEX] : NO_NAME);
|
||||
}
|
||||
function addMappingInternal(skipable, map, mapping) {
|
||||
const { generated, source, original, name, content } = mapping;
|
||||
if (!source) {
|
||||
return addSegmentInternal(
|
||||
skipable,
|
||||
map,
|
||||
generated.line - 1,
|
||||
generated.column,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
assert(original);
|
||||
return addSegmentInternal(
|
||||
skipable,
|
||||
map,
|
||||
generated.line - 1,
|
||||
generated.column,
|
||||
source,
|
||||
original.line - 1,
|
||||
original.column,
|
||||
name,
|
||||
content
|
||||
);
|
||||
}
|
||||
}));
|
||||
//# sourceMappingURL=gen-mapping.umd.js.map
|
||||
6
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js.map
generated
vendored
Normal file
6
node_modules/@jridgewell/gen-mapping/dist/gen-mapping.umd.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
88
node_modules/@jridgewell/gen-mapping/dist/types/gen-mapping.d.ts
generated
vendored
Normal file
88
node_modules/@jridgewell/gen-mapping/dist/types/gen-mapping.d.ts
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
import type { SourceMapInput } from '@jridgewell/trace-mapping';
|
||||
import type { DecodedSourceMap, EncodedSourceMap, Pos, Mapping } from './types';
|
||||
export type { DecodedSourceMap, EncodedSourceMap, Mapping };
|
||||
export type Options = {
|
||||
file?: string | null;
|
||||
sourceRoot?: string | null;
|
||||
};
|
||||
/**
|
||||
* Provides the state to generate a sourcemap.
|
||||
*/
|
||||
export declare class GenMapping {
|
||||
private _names;
|
||||
private _sources;
|
||||
private _sourcesContent;
|
||||
private _mappings;
|
||||
private _ignoreList;
|
||||
file: string | null | undefined;
|
||||
sourceRoot: string | null | undefined;
|
||||
constructor({ file, sourceRoot }?: Options);
|
||||
}
|
||||
/**
|
||||
* A low-level API to associate a generated position with an original source position. Line and
|
||||
* column here are 0-based, unlike `addMapping`.
|
||||
*/
|
||||
export declare function addSegment(map: GenMapping, genLine: number, genColumn: number, source?: null, sourceLine?: null, sourceColumn?: null, name?: null, content?: null): void;
|
||||
export declare function addSegment(map: GenMapping, genLine: number, genColumn: number, source: string, sourceLine: number, sourceColumn: number, name?: null, content?: string | null): void;
|
||||
export declare function addSegment(map: GenMapping, genLine: number, genColumn: number, source: string, sourceLine: number, sourceColumn: number, name: string, content?: string | null): void;
|
||||
/**
|
||||
* A high-level API to associate a generated position with an original source position. Line is
|
||||
* 1-based, but column is 0-based, due to legacy behavior in `source-map` library.
|
||||
*/
|
||||
export declare function addMapping(map: GenMapping, mapping: {
|
||||
generated: Pos;
|
||||
source?: null;
|
||||
original?: null;
|
||||
name?: null;
|
||||
content?: null;
|
||||
}): void;
|
||||
export declare function addMapping(map: GenMapping, mapping: {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name?: null;
|
||||
content?: string | null;
|
||||
}): void;
|
||||
export declare function addMapping(map: GenMapping, mapping: {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: string;
|
||||
content?: string | null;
|
||||
}): void;
|
||||
/**
|
||||
* Same as `addSegment`, but will only add the segment if it generates useful information in the
|
||||
* resulting map. This only works correctly if segments are added **in order**, meaning you should
|
||||
* not add a segment with a lower generated line/column than one that came before.
|
||||
*/
|
||||
export declare const maybeAddSegment: typeof addSegment;
|
||||
/**
|
||||
* Same as `addMapping`, but will only add the mapping if it generates useful information in the
|
||||
* resulting map. This only works correctly if mappings are added **in order**, meaning you should
|
||||
* not add a mapping with a lower generated line/column than one that came before.
|
||||
*/
|
||||
export declare const maybeAddMapping: typeof addMapping;
|
||||
/**
|
||||
* Adds/removes the content of the source file to the source map.
|
||||
*/
|
||||
export declare function setSourceContent(map: GenMapping, source: string, content: string | null): void;
|
||||
export declare function setIgnore(map: GenMapping, source: string, ignore?: boolean): void;
|
||||
/**
|
||||
* Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
|
||||
* a sourcemap, or to JSON.stringify.
|
||||
*/
|
||||
export declare function toDecodedMap(map: GenMapping): DecodedSourceMap;
|
||||
/**
|
||||
* Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
|
||||
* a sourcemap, or to JSON.stringify.
|
||||
*/
|
||||
export declare function toEncodedMap(map: GenMapping): EncodedSourceMap;
|
||||
/**
|
||||
* Constructs a new GenMapping, using the already present mappings of the input.
|
||||
*/
|
||||
export declare function fromMap(input: SourceMapInput): GenMapping;
|
||||
/**
|
||||
* Returns an array of high-level mapping objects for every recorded segment, which could then be
|
||||
* passed to the `source-map` library.
|
||||
*/
|
||||
export declare function allMappings(map: GenMapping): Mapping[];
|
||||
32
node_modules/@jridgewell/gen-mapping/dist/types/set-array.d.ts
generated
vendored
Normal file
32
node_modules/@jridgewell/gen-mapping/dist/types/set-array.d.ts
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
type Key = string | number | symbol;
|
||||
/**
|
||||
* SetArray acts like a `Set` (allowing only one occurrence of a string `key`), but provides the
|
||||
* index of the `key` in the backing array.
|
||||
*
|
||||
* This is designed to allow synchronizing a second array with the contents of the backing array,
|
||||
* like how in a sourcemap `sourcesContent[i]` is the source content associated with `source[i]`,
|
||||
* and there are never duplicates.
|
||||
*/
|
||||
export declare class SetArray<T extends Key = Key> {
|
||||
private _indexes;
|
||||
array: readonly T[];
|
||||
constructor();
|
||||
}
|
||||
/**
|
||||
* Gets the index associated with `key` in the backing array, if it is already present.
|
||||
*/
|
||||
export declare function get<T extends Key>(setarr: SetArray<T>, key: T): number | undefined;
|
||||
/**
|
||||
* Puts `key` into the backing array, if it is not already present. Returns
|
||||
* the index of the `key` in the backing array.
|
||||
*/
|
||||
export declare function put<T extends Key>(setarr: SetArray<T>, key: T): number;
|
||||
/**
|
||||
* Pops the last added item out of the SetArray.
|
||||
*/
|
||||
export declare function pop<T extends Key>(setarr: SetArray<T>): void;
|
||||
/**
|
||||
* Removes the key, if it exists in the set.
|
||||
*/
|
||||
export declare function remove<T extends Key>(setarr: SetArray<T>, key: T): void;
|
||||
export {};
|
||||
12
node_modules/@jridgewell/gen-mapping/dist/types/sourcemap-segment.d.ts
generated
vendored
Normal file
12
node_modules/@jridgewell/gen-mapping/dist/types/sourcemap-segment.d.ts
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
type GeneratedColumn = number;
|
||||
type SourcesIndex = number;
|
||||
type SourceLine = number;
|
||||
type SourceColumn = number;
|
||||
type NamesIndex = number;
|
||||
export type SourceMapSegment = [GeneratedColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn] | [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
|
||||
export declare const COLUMN = 0;
|
||||
export declare const SOURCES_INDEX = 1;
|
||||
export declare const SOURCE_LINE = 2;
|
||||
export declare const SOURCE_COLUMN = 3;
|
||||
export declare const NAMES_INDEX = 4;
|
||||
export {};
|
||||
43
node_modules/@jridgewell/gen-mapping/dist/types/types.d.ts
generated
vendored
Normal file
43
node_modules/@jridgewell/gen-mapping/dist/types/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { SourceMapSegment } from './sourcemap-segment';
|
||||
export interface SourceMapV3 {
|
||||
file?: string | null;
|
||||
names: readonly string[];
|
||||
sourceRoot?: string;
|
||||
sources: readonly (string | null)[];
|
||||
sourcesContent?: readonly (string | null)[];
|
||||
version: 3;
|
||||
ignoreList?: readonly number[];
|
||||
}
|
||||
export interface EncodedSourceMap extends SourceMapV3 {
|
||||
mappings: string;
|
||||
}
|
||||
export interface DecodedSourceMap extends SourceMapV3 {
|
||||
mappings: readonly SourceMapSegment[][];
|
||||
}
|
||||
export interface Pos {
|
||||
line: number;
|
||||
column: number;
|
||||
}
|
||||
export interface OriginalPos extends Pos {
|
||||
source: string;
|
||||
}
|
||||
export interface BindingExpressionRange {
|
||||
start: Pos;
|
||||
expression: string;
|
||||
}
|
||||
export type Mapping = {
|
||||
generated: Pos;
|
||||
source: undefined;
|
||||
original: undefined;
|
||||
name: undefined;
|
||||
} | {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: string;
|
||||
} | {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: undefined;
|
||||
};
|
||||
67
node_modules/@jridgewell/gen-mapping/package.json
generated
vendored
Normal file
67
node_modules/@jridgewell/gen-mapping/package.json
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "@jridgewell/gen-mapping",
|
||||
"version": "0.3.13",
|
||||
"description": "Generate source maps",
|
||||
"keywords": [
|
||||
"source",
|
||||
"map"
|
||||
],
|
||||
"main": "dist/gen-mapping.umd.js",
|
||||
"module": "dist/gen-mapping.mjs",
|
||||
"types": "types/gen-mapping.d.cts",
|
||||
"files": [
|
||||
"dist",
|
||||
"src",
|
||||
"types"
|
||||
],
|
||||
"exports": {
|
||||
".": [
|
||||
{
|
||||
"import": {
|
||||
"types": "./types/gen-mapping.d.mts",
|
||||
"default": "./dist/gen-mapping.mjs"
|
||||
},
|
||||
"default": {
|
||||
"types": "./types/gen-mapping.d.cts",
|
||||
"default": "./dist/gen-mapping.umd.js"
|
||||
}
|
||||
},
|
||||
"./dist/gen-mapping.umd.js"
|
||||
],
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"scripts": {
|
||||
"benchmark": "run-s build:code benchmark:*",
|
||||
"benchmark:install": "cd benchmark && npm install",
|
||||
"benchmark:only": "node --expose-gc benchmark/index.js",
|
||||
"build": "run-s -n build:code build:types",
|
||||
"build:code": "node ../../esbuild.mjs gen-mapping.ts",
|
||||
"build:types": "run-s build:types:force build:types:emit build:types:mts",
|
||||
"build:types:force": "rimraf tsconfig.build.tsbuildinfo",
|
||||
"build:types:emit": "tsc --project tsconfig.build.json",
|
||||
"build:types:mts": "node ../../mts-types.mjs",
|
||||
"clean": "run-s -n clean:code clean:types",
|
||||
"clean:code": "tsc --build --clean tsconfig.build.json",
|
||||
"clean:types": "rimraf dist types",
|
||||
"test": "run-s -n test:types test:only test:format",
|
||||
"test:format": "prettier --check '{src,test}/**/*.ts'",
|
||||
"test:only": "mocha",
|
||||
"test:types": "eslint '{src,test}/**/*.ts'",
|
||||
"lint": "run-s -n lint:types lint:format",
|
||||
"lint:format": "npm run test:format -- --write",
|
||||
"lint:types": "npm run test:types -- --fix",
|
||||
"prepublishOnly": "npm run-s -n build test"
|
||||
},
|
||||
"homepage": "https://github.com/jridgewell/sourcemaps/tree/main/packages/gen-mapping",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/jridgewell/sourcemaps.git",
|
||||
"directory": "packages/gen-mapping"
|
||||
},
|
||||
"author": "Justin Ridgewell <justin@ridgewell.name>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.24"
|
||||
}
|
||||
}
|
||||
614
node_modules/@jridgewell/gen-mapping/src/gen-mapping.ts
generated
vendored
Normal file
614
node_modules/@jridgewell/gen-mapping/src/gen-mapping.ts
generated
vendored
Normal file
@@ -0,0 +1,614 @@
|
||||
import { SetArray, put, remove } from './set-array';
|
||||
import {
|
||||
encode,
|
||||
// encodeGeneratedRanges,
|
||||
// encodeOriginalScopes
|
||||
} from '@jridgewell/sourcemap-codec';
|
||||
import { TraceMap, decodedMappings } from '@jridgewell/trace-mapping';
|
||||
|
||||
import {
|
||||
COLUMN,
|
||||
SOURCES_INDEX,
|
||||
SOURCE_LINE,
|
||||
SOURCE_COLUMN,
|
||||
NAMES_INDEX,
|
||||
} from './sourcemap-segment';
|
||||
|
||||
import type { SourceMapInput } from '@jridgewell/trace-mapping';
|
||||
// import type { OriginalScope, GeneratedRange } from '@jridgewell/sourcemap-codec';
|
||||
import type { SourceMapSegment } from './sourcemap-segment';
|
||||
import type {
|
||||
DecodedSourceMap,
|
||||
EncodedSourceMap,
|
||||
Pos,
|
||||
Mapping,
|
||||
// BindingExpressionRange,
|
||||
// OriginalPos,
|
||||
// OriginalScopeInfo,
|
||||
// GeneratedRangeInfo,
|
||||
} from './types';
|
||||
|
||||
export type { DecodedSourceMap, EncodedSourceMap, Mapping };
|
||||
|
||||
export type Options = {
|
||||
file?: string | null;
|
||||
sourceRoot?: string | null;
|
||||
};
|
||||
|
||||
const NO_NAME = -1;
|
||||
|
||||
/**
|
||||
* Provides the state to generate a sourcemap.
|
||||
*/
|
||||
export class GenMapping {
|
||||
declare private _names: SetArray<string>;
|
||||
declare private _sources: SetArray<string>;
|
||||
declare private _sourcesContent: (string | null)[];
|
||||
declare private _mappings: SourceMapSegment[][];
|
||||
// private declare _originalScopes: OriginalScope[][];
|
||||
// private declare _generatedRanges: GeneratedRange[];
|
||||
declare private _ignoreList: SetArray<number>;
|
||||
declare file: string | null | undefined;
|
||||
declare sourceRoot: string | null | undefined;
|
||||
|
||||
constructor({ file, sourceRoot }: Options = {}) {
|
||||
this._names = new SetArray();
|
||||
this._sources = new SetArray();
|
||||
this._sourcesContent = [];
|
||||
this._mappings = [];
|
||||
// this._originalScopes = [];
|
||||
// this._generatedRanges = [];
|
||||
this.file = file;
|
||||
this.sourceRoot = sourceRoot;
|
||||
this._ignoreList = new SetArray();
|
||||
}
|
||||
}
|
||||
|
||||
interface PublicMap {
|
||||
_names: GenMapping['_names'];
|
||||
_sources: GenMapping['_sources'];
|
||||
_sourcesContent: GenMapping['_sourcesContent'];
|
||||
_mappings: GenMapping['_mappings'];
|
||||
// _originalScopes: GenMapping['_originalScopes'];
|
||||
// _generatedRanges: GenMapping['_generatedRanges'];
|
||||
_ignoreList: GenMapping['_ignoreList'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Typescript doesn't allow friend access to private fields, so this just casts the map into a type
|
||||
* with public access modifiers.
|
||||
*/
|
||||
function cast(map: unknown): PublicMap {
|
||||
return map as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* A low-level API to associate a generated position with an original source position. Line and
|
||||
* column here are 0-based, unlike `addMapping`.
|
||||
*/
|
||||
export function addSegment(
|
||||
map: GenMapping,
|
||||
genLine: number,
|
||||
genColumn: number,
|
||||
source?: null,
|
||||
sourceLine?: null,
|
||||
sourceColumn?: null,
|
||||
name?: null,
|
||||
content?: null,
|
||||
): void;
|
||||
export function addSegment(
|
||||
map: GenMapping,
|
||||
genLine: number,
|
||||
genColumn: number,
|
||||
source: string,
|
||||
sourceLine: number,
|
||||
sourceColumn: number,
|
||||
name?: null,
|
||||
content?: string | null,
|
||||
): void;
|
||||
export function addSegment(
|
||||
map: GenMapping,
|
||||
genLine: number,
|
||||
genColumn: number,
|
||||
source: string,
|
||||
sourceLine: number,
|
||||
sourceColumn: number,
|
||||
name: string,
|
||||
content?: string | null,
|
||||
): void;
|
||||
export function addSegment(
|
||||
map: GenMapping,
|
||||
genLine: number,
|
||||
genColumn: number,
|
||||
source?: string | null,
|
||||
sourceLine?: number | null,
|
||||
sourceColumn?: number | null,
|
||||
name?: string | null,
|
||||
content?: string | null,
|
||||
): void {
|
||||
return addSegmentInternal(
|
||||
false,
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A high-level API to associate a generated position with an original source position. Line is
|
||||
* 1-based, but column is 0-based, due to legacy behavior in `source-map` library.
|
||||
*/
|
||||
export function addMapping(
|
||||
map: GenMapping,
|
||||
mapping: {
|
||||
generated: Pos;
|
||||
source?: null;
|
||||
original?: null;
|
||||
name?: null;
|
||||
content?: null;
|
||||
},
|
||||
): void;
|
||||
export function addMapping(
|
||||
map: GenMapping,
|
||||
mapping: {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name?: null;
|
||||
content?: string | null;
|
||||
},
|
||||
): void;
|
||||
export function addMapping(
|
||||
map: GenMapping,
|
||||
mapping: {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: string;
|
||||
content?: string | null;
|
||||
},
|
||||
): void;
|
||||
export function addMapping(
|
||||
map: GenMapping,
|
||||
mapping: {
|
||||
generated: Pos;
|
||||
source?: string | null;
|
||||
original?: Pos | null;
|
||||
name?: string | null;
|
||||
content?: string | null;
|
||||
},
|
||||
): void {
|
||||
return addMappingInternal(false, map, mapping as Parameters<typeof addMappingInternal>[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `addSegment`, but will only add the segment if it generates useful information in the
|
||||
* resulting map. This only works correctly if segments are added **in order**, meaning you should
|
||||
* not add a segment with a lower generated line/column than one that came before.
|
||||
*/
|
||||
export const maybeAddSegment: typeof addSegment = (
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content,
|
||||
) => {
|
||||
return addSegmentInternal(
|
||||
true,
|
||||
map,
|
||||
genLine,
|
||||
genColumn,
|
||||
source,
|
||||
sourceLine,
|
||||
sourceColumn,
|
||||
name,
|
||||
content,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Same as `addMapping`, but will only add the mapping if it generates useful information in the
|
||||
* resulting map. This only works correctly if mappings are added **in order**, meaning you should
|
||||
* not add a mapping with a lower generated line/column than one that came before.
|
||||
*/
|
||||
export const maybeAddMapping: typeof addMapping = (map, mapping) => {
|
||||
return addMappingInternal(true, map, mapping as Parameters<typeof addMappingInternal>[2]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds/removes the content of the source file to the source map.
|
||||
*/
|
||||
export function setSourceContent(map: GenMapping, source: string, content: string | null): void {
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast(map);
|
||||
const index = put(sources, source);
|
||||
sourcesContent[index] = content;
|
||||
// if (index === originalScopes.length) originalScopes[index] = [];
|
||||
}
|
||||
|
||||
export function setIgnore(map: GenMapping, source: string, ignore = true) {
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_ignoreList: ignoreList,
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast(map);
|
||||
const index = put(sources, source);
|
||||
if (index === sourcesContent.length) sourcesContent[index] = null;
|
||||
// if (index === originalScopes.length) originalScopes[index] = [];
|
||||
if (ignore) put(ignoreList, index);
|
||||
else remove(ignoreList, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
|
||||
* a sourcemap, or to JSON.stringify.
|
||||
*/
|
||||
export function toDecodedMap(map: GenMapping): DecodedSourceMap {
|
||||
const {
|
||||
_mappings: mappings,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_names: names,
|
||||
_ignoreList: ignoreList,
|
||||
// _originalScopes: originalScopes,
|
||||
// _generatedRanges: generatedRanges,
|
||||
} = cast(map);
|
||||
removeEmptyFinalLines(mappings);
|
||||
|
||||
return {
|
||||
version: 3,
|
||||
file: map.file || undefined,
|
||||
names: names.array,
|
||||
sourceRoot: map.sourceRoot || undefined,
|
||||
sources: sources.array,
|
||||
sourcesContent,
|
||||
mappings,
|
||||
// originalScopes,
|
||||
// generatedRanges,
|
||||
ignoreList: ignoreList.array,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
|
||||
* a sourcemap, or to JSON.stringify.
|
||||
*/
|
||||
export function toEncodedMap(map: GenMapping): EncodedSourceMap {
|
||||
const decoded = toDecodedMap(map);
|
||||
return Object.assign({}, decoded, {
|
||||
// originalScopes: decoded.originalScopes.map((os) => encodeOriginalScopes(os)),
|
||||
// generatedRanges: encodeGeneratedRanges(decoded.generatedRanges as GeneratedRange[]),
|
||||
mappings: encode(decoded.mappings as SourceMapSegment[][]),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new GenMapping, using the already present mappings of the input.
|
||||
*/
|
||||
export function fromMap(input: SourceMapInput): GenMapping {
|
||||
const map = new TraceMap(input);
|
||||
const gen = new GenMapping({ file: map.file, sourceRoot: map.sourceRoot });
|
||||
|
||||
putAll(cast(gen)._names, map.names);
|
||||
putAll(cast(gen)._sources, map.sources as string[]);
|
||||
cast(gen)._sourcesContent = map.sourcesContent || map.sources.map(() => null);
|
||||
cast(gen)._mappings = decodedMappings(map) as GenMapping['_mappings'];
|
||||
// TODO: implement originalScopes/generatedRanges
|
||||
if (map.ignoreList) putAll(cast(gen)._ignoreList, map.ignoreList);
|
||||
|
||||
return gen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of high-level mapping objects for every recorded segment, which could then be
|
||||
* passed to the `source-map` library.
|
||||
*/
|
||||
export function allMappings(map: GenMapping): Mapping[] {
|
||||
const out: Mapping[] = [];
|
||||
const { _mappings: mappings, _sources: sources, _names: names } = cast(map);
|
||||
|
||||
for (let i = 0; i < mappings.length; i++) {
|
||||
const line = mappings[i];
|
||||
for (let j = 0; j < line.length; j++) {
|
||||
const seg = line[j];
|
||||
|
||||
const generated = { line: i + 1, column: seg[COLUMN] };
|
||||
let source: string | undefined = undefined;
|
||||
let original: Pos | undefined = undefined;
|
||||
let name: string | undefined = undefined;
|
||||
|
||||
if (seg.length !== 1) {
|
||||
source = sources.array[seg[SOURCES_INDEX]];
|
||||
original = { line: seg[SOURCE_LINE] + 1, column: seg[SOURCE_COLUMN] };
|
||||
|
||||
if (seg.length === 5) name = names.array[seg[NAMES_INDEX]];
|
||||
}
|
||||
|
||||
out.push({ generated, source, original, name } as Mapping);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// This split declaration is only so that terser can elminiate the static initialization block.
|
||||
function addSegmentInternal<S extends string | null | undefined>(
|
||||
skipable: boolean,
|
||||
map: GenMapping,
|
||||
genLine: number,
|
||||
genColumn: number,
|
||||
source: S,
|
||||
sourceLine: S extends string ? number : null | undefined,
|
||||
sourceColumn: S extends string ? number : null | undefined,
|
||||
name: S extends string ? string | null | undefined : null | undefined,
|
||||
content: S extends string ? string | null | undefined : null | undefined,
|
||||
): void {
|
||||
const {
|
||||
_mappings: mappings,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_names: names,
|
||||
// _originalScopes: originalScopes,
|
||||
} = cast(map);
|
||||
const line = getIndex(mappings, genLine);
|
||||
const index = getColumnIndex(line, genColumn);
|
||||
|
||||
if (!source) {
|
||||
if (skipable && skipSourceless(line, index)) return;
|
||||
return insert(line, index, [genColumn]);
|
||||
}
|
||||
|
||||
// Sigh, TypeScript can't figure out sourceLine and sourceColumn aren't nullish if source
|
||||
// isn't nullish.
|
||||
assert<number>(sourceLine);
|
||||
assert<number>(sourceColumn);
|
||||
|
||||
const sourcesIndex = put(sources, source);
|
||||
const namesIndex = name ? put(names, name) : NO_NAME;
|
||||
if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content ?? null;
|
||||
// if (sourcesIndex === originalScopes.length) originalScopes[sourcesIndex] = [];
|
||||
|
||||
if (skipable && skipSource(line, index, sourcesIndex, sourceLine, sourceColumn, namesIndex)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return insert(
|
||||
line,
|
||||
index,
|
||||
name
|
||||
? [genColumn, sourcesIndex, sourceLine, sourceColumn, namesIndex]
|
||||
: [genColumn, sourcesIndex, sourceLine, sourceColumn],
|
||||
);
|
||||
}
|
||||
|
||||
function assert<T>(_val: unknown): asserts _val is T {
|
||||
// noop.
|
||||
}
|
||||
|
||||
function getIndex<T>(arr: T[][], index: number): T[] {
|
||||
for (let i = arr.length; i <= index; i++) {
|
||||
arr[i] = [];
|
||||
}
|
||||
return arr[index];
|
||||
}
|
||||
|
||||
function getColumnIndex(line: SourceMapSegment[], genColumn: number): number {
|
||||
let index = line.length;
|
||||
for (let i = index - 1; i >= 0; index = i--) {
|
||||
const current = line[i];
|
||||
if (genColumn >= current[COLUMN]) break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
function insert<T>(array: T[], index: number, value: T) {
|
||||
for (let i = array.length; i > index; i--) {
|
||||
array[i] = array[i - 1];
|
||||
}
|
||||
array[index] = value;
|
||||
}
|
||||
|
||||
function removeEmptyFinalLines(mappings: SourceMapSegment[][]) {
|
||||
const { length } = mappings;
|
||||
let len = length;
|
||||
for (let i = len - 1; i >= 0; len = i, i--) {
|
||||
if (mappings[i].length > 0) break;
|
||||
}
|
||||
if (len < length) mappings.length = len;
|
||||
}
|
||||
|
||||
function putAll<T extends string | number>(setarr: SetArray<T>, array: T[]) {
|
||||
for (let i = 0; i < array.length; i++) put(setarr, array[i]);
|
||||
}
|
||||
|
||||
function skipSourceless(line: SourceMapSegment[], index: number): boolean {
|
||||
// The start of a line is already sourceless, so adding a sourceless segment to the beginning
|
||||
// doesn't generate any useful information.
|
||||
if (index === 0) return true;
|
||||
|
||||
const prev = line[index - 1];
|
||||
// If the previous segment is also sourceless, then adding another sourceless segment doesn't
|
||||
// genrate any new information. Else, this segment will end the source/named segment and point to
|
||||
// a sourceless position, which is useful.
|
||||
return prev.length === 1;
|
||||
}
|
||||
|
||||
function skipSource(
|
||||
line: SourceMapSegment[],
|
||||
index: number,
|
||||
sourcesIndex: number,
|
||||
sourceLine: number,
|
||||
sourceColumn: number,
|
||||
namesIndex: number,
|
||||
): boolean {
|
||||
// A source/named segment at the start of a line gives position at that genColumn
|
||||
if (index === 0) return false;
|
||||
|
||||
const prev = line[index - 1];
|
||||
|
||||
// If the previous segment is sourceless, then we're transitioning to a source.
|
||||
if (prev.length === 1) return false;
|
||||
|
||||
// If the previous segment maps to the exact same source position, then this segment doesn't
|
||||
// provide any new position information.
|
||||
return (
|
||||
sourcesIndex === prev[SOURCES_INDEX] &&
|
||||
sourceLine === prev[SOURCE_LINE] &&
|
||||
sourceColumn === prev[SOURCE_COLUMN] &&
|
||||
namesIndex === (prev.length === 5 ? prev[NAMES_INDEX] : NO_NAME)
|
||||
);
|
||||
}
|
||||
|
||||
function addMappingInternal<S extends string | null | undefined>(
|
||||
skipable: boolean,
|
||||
map: GenMapping,
|
||||
mapping: {
|
||||
generated: Pos;
|
||||
source: S;
|
||||
original: S extends string ? Pos : null | undefined;
|
||||
name: S extends string ? string | null | undefined : null | undefined;
|
||||
content: S extends string ? string | null | undefined : null | undefined;
|
||||
},
|
||||
) {
|
||||
const { generated, source, original, name, content } = mapping;
|
||||
if (!source) {
|
||||
return addSegmentInternal(
|
||||
skipable,
|
||||
map,
|
||||
generated.line - 1,
|
||||
generated.column,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
);
|
||||
}
|
||||
assert<Pos>(original);
|
||||
return addSegmentInternal(
|
||||
skipable,
|
||||
map,
|
||||
generated.line - 1,
|
||||
generated.column,
|
||||
source as string,
|
||||
original.line - 1,
|
||||
original.column,
|
||||
name,
|
||||
content,
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
export function addOriginalScope(
|
||||
map: GenMapping,
|
||||
data: {
|
||||
start: Pos;
|
||||
end: Pos;
|
||||
source: string;
|
||||
kind: string;
|
||||
name?: string;
|
||||
variables?: string[];
|
||||
},
|
||||
): OriginalScopeInfo {
|
||||
const { start, end, source, kind, name, variables } = data;
|
||||
const {
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_originalScopes: originalScopes,
|
||||
_names: names,
|
||||
} = cast(map);
|
||||
const index = put(sources, source);
|
||||
if (index === sourcesContent.length) sourcesContent[index] = null;
|
||||
if (index === originalScopes.length) originalScopes[index] = [];
|
||||
|
||||
const kindIndex = put(names, kind);
|
||||
const scope: OriginalScope = name
|
||||
? [start.line - 1, start.column, end.line - 1, end.column, kindIndex, put(names, name)]
|
||||
: [start.line - 1, start.column, end.line - 1, end.column, kindIndex];
|
||||
if (variables) {
|
||||
scope.vars = variables.map((v) => put(names, v));
|
||||
}
|
||||
const len = originalScopes[index].push(scope);
|
||||
return [index, len - 1, variables];
|
||||
}
|
||||
*/
|
||||
|
||||
// Generated Ranges
|
||||
/*
|
||||
export function addGeneratedRange(
|
||||
map: GenMapping,
|
||||
data: {
|
||||
start: Pos;
|
||||
isScope: boolean;
|
||||
originalScope?: OriginalScopeInfo;
|
||||
callsite?: OriginalPos;
|
||||
},
|
||||
): GeneratedRangeInfo {
|
||||
const { start, isScope, originalScope, callsite } = data;
|
||||
const {
|
||||
_originalScopes: originalScopes,
|
||||
_sources: sources,
|
||||
_sourcesContent: sourcesContent,
|
||||
_generatedRanges: generatedRanges,
|
||||
} = cast(map);
|
||||
|
||||
const range: GeneratedRange = [
|
||||
start.line - 1,
|
||||
start.column,
|
||||
0,
|
||||
0,
|
||||
originalScope ? originalScope[0] : -1,
|
||||
originalScope ? originalScope[1] : -1,
|
||||
];
|
||||
if (originalScope?.[2]) {
|
||||
range.bindings = originalScope[2].map(() => [[-1]]);
|
||||
}
|
||||
if (callsite) {
|
||||
const index = put(sources, callsite.source);
|
||||
if (index === sourcesContent.length) sourcesContent[index] = null;
|
||||
if (index === originalScopes.length) originalScopes[index] = [];
|
||||
range.callsite = [index, callsite.line - 1, callsite.column];
|
||||
}
|
||||
if (isScope) range.isScope = true;
|
||||
generatedRanges.push(range);
|
||||
|
||||
return [range, originalScope?.[2]];
|
||||
}
|
||||
|
||||
export function setEndPosition(range: GeneratedRangeInfo, pos: Pos) {
|
||||
range[0][2] = pos.line - 1;
|
||||
range[0][3] = pos.column;
|
||||
}
|
||||
|
||||
export function addBinding(
|
||||
map: GenMapping,
|
||||
range: GeneratedRangeInfo,
|
||||
variable: string,
|
||||
expression: string | BindingExpressionRange,
|
||||
) {
|
||||
const { _names: names } = cast(map);
|
||||
const bindings = (range[0].bindings ||= []);
|
||||
const vars = range[1];
|
||||
|
||||
const index = vars!.indexOf(variable);
|
||||
const binding = getIndex(bindings, index);
|
||||
|
||||
if (typeof expression === 'string') binding[0] = [put(names, expression)];
|
||||
else {
|
||||
const { start } = expression;
|
||||
binding.push([put(names, expression.expression), start.line - 1, start.column]);
|
||||
}
|
||||
}
|
||||
*/
|
||||
82
node_modules/@jridgewell/gen-mapping/src/set-array.ts
generated
vendored
Normal file
82
node_modules/@jridgewell/gen-mapping/src/set-array.ts
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
type Key = string | number | symbol;
|
||||
|
||||
/**
|
||||
* SetArray acts like a `Set` (allowing only one occurrence of a string `key`), but provides the
|
||||
* index of the `key` in the backing array.
|
||||
*
|
||||
* This is designed to allow synchronizing a second array with the contents of the backing array,
|
||||
* like how in a sourcemap `sourcesContent[i]` is the source content associated with `source[i]`,
|
||||
* and there are never duplicates.
|
||||
*/
|
||||
export class SetArray<T extends Key = Key> {
|
||||
declare private _indexes: Record<T, number | undefined>;
|
||||
declare array: readonly T[];
|
||||
|
||||
constructor() {
|
||||
this._indexes = { __proto__: null } as any;
|
||||
this.array = [];
|
||||
}
|
||||
}
|
||||
|
||||
interface PublicSet<T extends Key> {
|
||||
array: T[];
|
||||
_indexes: SetArray<T>['_indexes'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Typescript doesn't allow friend access to private fields, so this just casts the set into a type
|
||||
* with public access modifiers.
|
||||
*/
|
||||
function cast<T extends Key>(set: SetArray<T>): PublicSet<T> {
|
||||
return set as any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index associated with `key` in the backing array, if it is already present.
|
||||
*/
|
||||
export function get<T extends Key>(setarr: SetArray<T>, key: T): number | undefined {
|
||||
return cast(setarr)._indexes[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts `key` into the backing array, if it is not already present. Returns
|
||||
* the index of the `key` in the backing array.
|
||||
*/
|
||||
export function put<T extends Key>(setarr: SetArray<T>, key: T): number {
|
||||
// The key may or may not be present. If it is present, it's a number.
|
||||
const index = get(setarr, key);
|
||||
if (index !== undefined) return index;
|
||||
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
|
||||
const length = array.push(key);
|
||||
return (indexes[key] = length - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pops the last added item out of the SetArray.
|
||||
*/
|
||||
export function pop<T extends Key>(setarr: SetArray<T>): void {
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
if (array.length === 0) return;
|
||||
|
||||
const last = array.pop()!;
|
||||
indexes[last] = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the key, if it exists in the set.
|
||||
*/
|
||||
export function remove<T extends Key>(setarr: SetArray<T>, key: T): void {
|
||||
const index = get(setarr, key);
|
||||
if (index === undefined) return;
|
||||
|
||||
const { array, _indexes: indexes } = cast(setarr);
|
||||
for (let i = index + 1; i < array.length; i++) {
|
||||
const k = array[i];
|
||||
array[i - 1] = k;
|
||||
indexes[k]!--;
|
||||
}
|
||||
indexes[key] = undefined;
|
||||
array.pop();
|
||||
}
|
||||
16
node_modules/@jridgewell/gen-mapping/src/sourcemap-segment.ts
generated
vendored
Normal file
16
node_modules/@jridgewell/gen-mapping/src/sourcemap-segment.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
type GeneratedColumn = number;
|
||||
type SourcesIndex = number;
|
||||
type SourceLine = number;
|
||||
type SourceColumn = number;
|
||||
type NamesIndex = number;
|
||||
|
||||
export type SourceMapSegment =
|
||||
| [GeneratedColumn]
|
||||
| [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn]
|
||||
| [GeneratedColumn, SourcesIndex, SourceLine, SourceColumn, NamesIndex];
|
||||
|
||||
export const COLUMN = 0;
|
||||
export const SOURCES_INDEX = 1;
|
||||
export const SOURCE_LINE = 2;
|
||||
export const SOURCE_COLUMN = 3;
|
||||
export const NAMES_INDEX = 4;
|
||||
61
node_modules/@jridgewell/gen-mapping/src/types.ts
generated
vendored
Normal file
61
node_modules/@jridgewell/gen-mapping/src/types.ts
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// import type { GeneratedRange, OriginalScope } from '@jridgewell/sourcemap-codec';
|
||||
import type { SourceMapSegment } from './sourcemap-segment';
|
||||
|
||||
export interface SourceMapV3 {
|
||||
file?: string | null;
|
||||
names: readonly string[];
|
||||
sourceRoot?: string;
|
||||
sources: readonly (string | null)[];
|
||||
sourcesContent?: readonly (string | null)[];
|
||||
version: 3;
|
||||
ignoreList?: readonly number[];
|
||||
}
|
||||
|
||||
export interface EncodedSourceMap extends SourceMapV3 {
|
||||
mappings: string;
|
||||
// originalScopes: string[];
|
||||
// generatedRanges: string;
|
||||
}
|
||||
|
||||
export interface DecodedSourceMap extends SourceMapV3 {
|
||||
mappings: readonly SourceMapSegment[][];
|
||||
// originalScopes: readonly OriginalScope[][];
|
||||
// generatedRanges: readonly GeneratedRange[];
|
||||
}
|
||||
|
||||
export interface Pos {
|
||||
line: number; // 1-based
|
||||
column: number; // 0-based
|
||||
}
|
||||
|
||||
export interface OriginalPos extends Pos {
|
||||
source: string;
|
||||
}
|
||||
|
||||
export interface BindingExpressionRange {
|
||||
start: Pos;
|
||||
expression: string;
|
||||
}
|
||||
|
||||
// export type OriginalScopeInfo = [number, number, string[] | undefined];
|
||||
// export type GeneratedRangeInfo = [GeneratedRange, string[] | undefined];
|
||||
|
||||
export type Mapping =
|
||||
| {
|
||||
generated: Pos;
|
||||
source: undefined;
|
||||
original: undefined;
|
||||
name: undefined;
|
||||
}
|
||||
| {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: string;
|
||||
}
|
||||
| {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: undefined;
|
||||
};
|
||||
89
node_modules/@jridgewell/gen-mapping/types/gen-mapping.d.cts
generated
vendored
Normal file
89
node_modules/@jridgewell/gen-mapping/types/gen-mapping.d.cts
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
import type { SourceMapInput } from '@jridgewell/trace-mapping';
|
||||
import type { DecodedSourceMap, EncodedSourceMap, Pos, Mapping } from './types.cts';
|
||||
export type { DecodedSourceMap, EncodedSourceMap, Mapping };
|
||||
export type Options = {
|
||||
file?: string | null;
|
||||
sourceRoot?: string | null;
|
||||
};
|
||||
/**
|
||||
* Provides the state to generate a sourcemap.
|
||||
*/
|
||||
export declare class GenMapping {
|
||||
private _names;
|
||||
private _sources;
|
||||
private _sourcesContent;
|
||||
private _mappings;
|
||||
private _ignoreList;
|
||||
file: string | null | undefined;
|
||||
sourceRoot: string | null | undefined;
|
||||
constructor({ file, sourceRoot }?: Options);
|
||||
}
|
||||
/**
|
||||
* A low-level API to associate a generated position with an original source position. Line and
|
||||
* column here are 0-based, unlike `addMapping`.
|
||||
*/
|
||||
export declare function addSegment(map: GenMapping, genLine: number, genColumn: number, source?: null, sourceLine?: null, sourceColumn?: null, name?: null, content?: null): void;
|
||||
export declare function addSegment(map: GenMapping, genLine: number, genColumn: number, source: string, sourceLine: number, sourceColumn: number, name?: null, content?: string | null): void;
|
||||
export declare function addSegment(map: GenMapping, genLine: number, genColumn: number, source: string, sourceLine: number, sourceColumn: number, name: string, content?: string | null): void;
|
||||
/**
|
||||
* A high-level API to associate a generated position with an original source position. Line is
|
||||
* 1-based, but column is 0-based, due to legacy behavior in `source-map` library.
|
||||
*/
|
||||
export declare function addMapping(map: GenMapping, mapping: {
|
||||
generated: Pos;
|
||||
source?: null;
|
||||
original?: null;
|
||||
name?: null;
|
||||
content?: null;
|
||||
}): void;
|
||||
export declare function addMapping(map: GenMapping, mapping: {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name?: null;
|
||||
content?: string | null;
|
||||
}): void;
|
||||
export declare function addMapping(map: GenMapping, mapping: {
|
||||
generated: Pos;
|
||||
source: string;
|
||||
original: Pos;
|
||||
name: string;
|
||||
content?: string | null;
|
||||
}): void;
|
||||
/**
|
||||
* Same as `addSegment`, but will only add the segment if it generates useful information in the
|
||||
* resulting map. This only works correctly if segments are added **in order**, meaning you should
|
||||
* not add a segment with a lower generated line/column than one that came before.
|
||||
*/
|
||||
export declare const maybeAddSegment: typeof addSegment;
|
||||
/**
|
||||
* Same as `addMapping`, but will only add the mapping if it generates useful information in the
|
||||
* resulting map. This only works correctly if mappings are added **in order**, meaning you should
|
||||
* not add a mapping with a lower generated line/column than one that came before.
|
||||
*/
|
||||
export declare const maybeAddMapping: typeof addMapping;
|
||||
/**
|
||||
* Adds/removes the content of the source file to the source map.
|
||||
*/
|
||||
export declare function setSourceContent(map: GenMapping, source: string, content: string | null): void;
|
||||
export declare function setIgnore(map: GenMapping, source: string, ignore?: boolean): void;
|
||||
/**
|
||||
* Returns a sourcemap object (with decoded mappings) suitable for passing to a library that expects
|
||||
* a sourcemap, or to JSON.stringify.
|
||||
*/
|
||||
export declare function toDecodedMap(map: GenMapping): DecodedSourceMap;
|
||||
/**
|
||||
* Returns a sourcemap object (with encoded mappings) suitable for passing to a library that expects
|
||||
* a sourcemap, or to JSON.stringify.
|
||||
*/
|
||||
export declare function toEncodedMap(map: GenMapping): EncodedSourceMap;
|
||||
/**
|
||||
* Constructs a new GenMapping, using the already present mappings of the input.
|
||||
*/
|
||||
export declare function fromMap(input: SourceMapInput): GenMapping;
|
||||
/**
|
||||
* Returns an array of high-level mapping objects for every recorded segment, which could then be
|
||||
* passed to the `source-map` library.
|
||||
*/
|
||||
export declare function allMappings(map: GenMapping): Mapping[];
|
||||
//# sourceMappingURL=gen-mapping.d.ts.map
|
||||
1
node_modules/@jridgewell/gen-mapping/types/gen-mapping.d.cts.map
generated
vendored
Normal file
1
node_modules/@jridgewell/gen-mapping/types/gen-mapping.d.cts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"gen-mapping.d.ts","sourceRoot":"","sources":["../src/gen-mapping.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGhE,OAAO,KAAK,EACV,gBAAgB,EAChB,gBAAgB,EAChB,GAAG,EACH,OAAO,EAKR,MAAM,SAAS,CAAC;AAEjB,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;AAE5D,MAAM,MAAM,OAAO,GAAG;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC;AAIF;;GAEG;AACH,qBAAa,UAAU;IACrB,QAAgB,MAAM,CAAmB;IACzC,QAAgB,QAAQ,CAAmB;IAC3C,QAAgB,eAAe,CAAoB;IACnD,QAAgB,SAAS,CAAuB;IAGhD,QAAgB,WAAW,CAAmB;IACtC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;gBAElC,EAAE,IAAI,EAAE,UAAU,EAAE,GAAE,OAAY;CAW/C;AAoBD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,IAAI,EACb,UAAU,CAAC,EAAE,IAAI,EACjB,YAAY,CAAC,EAAE,IAAI,EACnB,IAAI,CAAC,EAAE,IAAI,EACX,OAAO,CAAC,EAAE,IAAI,GACb,IAAI,CAAC;AACR,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,IAAI,CAAC,EAAE,IAAI,EACX,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GACtB,IAAI,CAAC;AACR,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GACtB,IAAI,CAAC;AAwBR;;;GAGG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE;IACP,SAAS,EAAE,GAAG,CAAC;IACf,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,OAAO,CAAC,EAAE,IAAI,CAAC;CAChB,GACA,IAAI,CAAC;AACR,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE;IACP,SAAS,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GACA,IAAI,CAAC;AACR,wBAAgB,UAAU,CACxB,GAAG,EAAE,UAAU,EACf,OAAO,EAAE;IACP,SAAS,EAAE,GAAG,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,GAAG,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,GACA,IAAI,CAAC;AAcR;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,UAqBpC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,OAAO,UAEpC,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAS9F;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAO,QAYvE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,gBAAgB,CAwB9D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,gBAAgB,CAO9D;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAYzD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,EAAE,CA0BtD"}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user