mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-14 00:06:17 -08:00
refactor(dash): [PKG-DASH-04] migrate strict TypeScript and compatible declarations
This commit is contained in:
1 parent
7de04573b6
commit
6840544e0e
38 files changed
+1744
-102
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,49 @@
|
||||
# PKG-DASH-04:DASH 严格 TS 与兼容公开类型
|
||||
|
||||
起点 `7de04573`。四个已拆分 JS 模块迁移为 TS,新增 `src/types.ts` 描述窄宿主、两代 SDK
|
||||
方法、selector/menu、事件和资源类型。纳入 strict/noUncheckedIndexedAccess,未加入 any、
|
||||
通配模块声明或 dash.js 依赖。源码工厂直接使用公开 Option/Result,并有双向可赋值夹具。
|
||||
|
||||
## 类型兼容
|
||||
|
||||
保留原 .d.ts 入口、工厂与字面量插件名、同步 update、单参数无接收者的 getName。
|
||||
新增 QualityLevel/AudioTrack/Config/Option/Result 命名类型及自定义 SDK 泛型;旧 object
|
||||
回调依然可用。可选重载允许运行时原本支持的省略/undefined,最后保留必填重载以保护
|
||||
`Parameters<typeof factory>[0]['quality']`。不要求消费者改变现有调用。
|
||||
|
||||
增加 ESM/CommonJS 类型桥和 legacy 的旧解析路径,所有 JS 分发文件路径不变。
|
||||
原始 npm 声明的 legacy 消费夹具在 TS 4.3.5/5.9.3 通过,候选运行同样夹具也通过。
|
||||
五种 TS/模块模式的新消费者零诊断,移除 expect-error 后八条非法调用全部被拒绝。
|
||||
|
||||
有限断言位于外部 art.dash 宿主、选定 SDK 方法族、非空轨道回退、Auto 与数字键边界。
|
||||
内部类型保留 SDK 字段缺失可能;断言不引入运行时修正,不把不完整 SDK 静默变成成功。
|
||||
源码与前一步运行代码相比只有局部别名和类型擦除,已知行为修正仍由 03 的契约测试保护。
|
||||
详情见 [包内架构](../../packages/artplayer-plugin-dash-control/ARCHITECTURE.md)。
|
||||
|
||||
## 编辑器与验证
|
||||
|
||||
build:ts 将 DASH 加入已存在的 AST 生成器,生成可独立编译的 callable/global 类型桥,
|
||||
避免旧 default export 与 export= 混用。实际生成文件有可重复生成、TS 4.3/5.9 正反例验证。
|
||||
新增 Monaco worker 用例,加载真实声明、检查回调/旧类型提取、拒绝错误返回并执行编译输出。
|
||||
没有手改 docs/assets/ts,产物由标准脚本生成。实际 SDK 的类型/媒体组合仍由 05 核验。
|
||||
|
||||
新增 `yarn test:dash-types-package`,使用现有打包检查和隔离目录工具,在工作区外离线安装
|
||||
核心与 DASH tarball,冻结锁重装,逐文件核对实际安装字节,编译时禁止回工作区解析类型。
|
||||
首次打包发现新增 tsconfig.json 泄露,先保留失败再补 .npmignore;最终五种模式及每组八条
|
||||
非法调用通过。此脚本只验收隔离类型,不替代 06 的完整运行时分发验收。
|
||||
|
||||
最终证据见 [冻结记录](../baselines/dash-types-validation.json):
|
||||
|
||||
| 验证 | 结果 |
|
||||
| --- | --- |
|
||||
| 严格源码 | DASH 5 个自有 TS 模块,全仓 261 个生产 TS 文件通过 |
|
||||
| 声明与隔离类型 | 新增 3 项类型基线通过;工作区与隔离 tarball 各 5 种模式,8 条非法用法均拒绝;旧实际 npm 声明对照通过 |
|
||||
| 运行时 | 源码 116 项、带三格式的 Node 266 项通过 |
|
||||
| 浏览器 | main 90 项(含核心/DASH Monaco 6 项)、legacy 84 项通过,无重试/跳过 |
|
||||
| 完整 CI | 715 项:661 单元、14 工程、40 基线;隔离打包脚本随后独立执行并通过 |
|
||||
| 构建 | 标准 build / build:ts 通过,三份 dist 与 docs/compiled 字节一致 |
|
||||
|
||||
DASH-TYPE-01 关闭;DASH-SDK-01/DASH-STATE-01、实际 SDK 类型/媒体及设备仍由 05 接续。
|
||||
当前 217 项:74 done、3 doing、140 todo。没有增加依赖、改变版本或发布。
|
||||
本地独立提交,回退同时恢复前一步 JS、声明和生成方式;保留 01~03 的基线与修复。
|
||||
下一步 05 完成真实 dash.js 4.5.2/5.2.1 媒体、组合和示例验证,06 接续隔离安装/分发。
|
||||
@@ -1,7 +1,8 @@
|
||||
# DASH Control 验证与维护入口
|
||||
|
||||
测试保护真实 npm 1.1.0 的既有调用契约,以及重构前工作区的 SDK 5.x 稳定 ID 修正。
|
||||
版本来源见 [发布契约](baselines/dash-control-contract.md)。02 建立基线,03 已改造生产实现;
|
||||
版本来源见 [发布契约](baselines/dash-control-contract.md)。02 建立基线,03 改造运行行为,
|
||||
04 已把五个自有模块迁移为严格 TS 并补齐公开类型与编辑器生成;
|
||||
实际模块地图与生命周期规则见 [包内架构](../packages/artplayer-plugin-dash-control/ARCHITECTURE.md)。
|
||||
|
||||
## 可重跑的测试
|
||||
@@ -12,6 +13,12 @@
|
||||
候选插件 SDK 4/5、两类菜单、两种选择及候选清理、Chromium/Firefox/WebKit。
|
||||
浏览器套件串行运行,避免共享端口和报告覆盖。
|
||||
- `yarn ci:check`:工具链、计划、lint、声明漂移、严格类型和 Node/基线测试。
|
||||
- `yarn test:browser test/browser/dash-editor-types.spec.js --trace on`:三引擎 Monaco 实际
|
||||
worker 编译全局声明、验证回调/旧类型提取及错误诊断,并执行发出的 JS 工厂。
|
||||
- `yarn build:ts`:重新生成编辑器声明;`refactor/scripts/dash-types.test.mjs` 校验可复现、
|
||||
TS 4.3.5/5.9.3、五种模块模式、八条非法用法及实际 npm 旧声明的消费者对照。
|
||||
- `yarn test:dash-types-package`:Yarn 打包核心/DASH、工作区外离线安装与冻结锁重装,
|
||||
检查五种模式、CommonJS callable/命名空间、每模式八条非法调用,并拒绝解析回工作区。
|
||||
|
||||
Node helper 分别加载当前源码、固定 Git 提交的旧工作区 UMD、实际 npm main/legacy/module。
|
||||
Git 内容以 LF 指纹核对,发布归档与成员以原始字节指纹核对。`ARTPLAYER_TEST_DASH` 可指定
|
||||
@@ -45,5 +52,5 @@ Git 内容以 LF 指纹核对,发布归档与成员以原始字节指纹核对
|
||||
- DASH-LIFE-01:空列表/禁用后 UI、旧回调、销毁后 update/订阅已修正,补充重入和错误回归。
|
||||
- DASH-STATE-01:唯一克隆当前轨道、重复标签、数字零 ID 已修正;实际 SDK 轨道身份仍由 05 核验。
|
||||
|
||||
状态以 risks.json 为准;受控修复不替代真实 SDK 验收。04 完成严格 TS/公开类型兼容,05 完成
|
||||
状态以 risks.json 为准;受控修复不替代真实 SDK 验收。严格 TS/公开类型已有独立验证,05 完成
|
||||
真实 SDK/媒体/组合验证,06 完成包分发验收。物理设备和 npm 发布准入仍待完成。
|
||||
@@ -0,0 +1,12 @@
|
||||
import Artplayer from 'artplayer'
|
||||
import dashControl from 'artplayer-plugin-dash-control'
|
||||
|
||||
type OldOption = Parameters<typeof dashControl>[0]
|
||||
type OldQuality = NonNullable<OldOption['quality']>
|
||||
const options: OldOption = { quality: { control: true, getName: (level: object) => String(level) }, audio: { setting: true } }
|
||||
const quality: OldQuality = { title: 'Quality', auto: 'Auto' }
|
||||
const formatter: NonNullable<OldQuality['getName']> = value => String(value)
|
||||
const art = new Artplayer({ container: '#player', url: 'video.mpd', plugins: [dashControl(options)] })
|
||||
const plugin: { name: 'artplayerPluginDashControl', update: () => void } = dashControl({ quality })(art)
|
||||
const done: void = plugin.update()
|
||||
void [formatter, done]
|
||||
+3
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 217 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 141 / doing 3 / blocked 0 / done 73 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 140 / doing 3 / blocked 0 / done 74 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
| PKG-DASH-01 | artplayer-plugin-dash-control<br>核对包契约与历史用法 | BASE-05 | quality/audio、representation ID/Auto、getName 和 update | 源码/声明/README/demo/发布包差异已登记;公开形状和版本范围冻结 | H | done |
|
||||
| PKG-DASH-02 | artplayer-plugin-dash-control<br>建立特有行为与错误测试 | PKG-DASH-01, ENG-03, ENG-05 | 保留已有 5 项稳定 ID 回归,补发布版 SDK 4.x/当前 5.x、音轨/空列表/过滤/换源与关闭引用 | 旧版本行为可重跑,成功/失败/切源/销毁有必要断言 | H | done |
|
||||
| PKG-DASH-03 | artplayer-plugin-dash-control<br>整理内部职责与资源 | PKG-DASH-02, CORE-11, CORE-14 | 能力适配保留 SDK 4.x 与 5.x,稳定 ID 映射、ABR 状态、UI 清理和生命周期职责分离 | 结构变化和缺陷修复分开记录;原 API/事件/资源生命周期通过 | H | done |
|
||||
| PKG-DASH-04 | artplayer-plugin-dash-control<br>迁移自有源码和公开类型 | PKG-DASH-03, ENG-04, ENG-06, CORE-07 | dash.js adapter、selector 和回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | todo |
|
||||
| PKG-DASH-04 | artplayer-plugin-dash-control<br>迁移自有源码和公开类型 | PKG-DASH-03, ENG-04, ENG-06, CORE-07 | dash.js adapter、selector 和回调类型 | 严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容 | H | done |
|
||||
| PKG-DASH-05 | artplayer-plugin-dash-control<br>验证新旧核心和组合 | PKG-DASH-04, CORE-22 | 固定 dash.js 4.5.2/5.2.1 与本地 DASH 实际清晰度/音轨、高亮、Auto 和换源组合 | 最终核心与原支持范围核心分别通过;设备/SDK 缺证据不能标完成 | H | todo |
|
||||
| PKG-DASH-06 | artplayer-plugin-dash-control<br>验证分发并同步文档 | PKG-DASH-05, ENG-07 | dash.control.js、支持的 dash.js 版本与产物 | tarball 入口/资源、类型、8082 demo 和 README 一致,有回退记录 | H | todo |
|
||||
|
||||
@@ -482,3 +482,4 @@
|
||||
- PKG-DASH-01: [记录](changes/2026-09-12-PKG-DASH-01-contract.md) [记录](baselines/dash-control-contract.md) [记录](baselines/dash-control-release.json)
|
||||
- PKG-DASH-02: [记录](changes/2026-09-12-PKG-DASH-02-tests.md) [记录](dash-validation.md) [记录](baselines/dash-validation.json)
|
||||
- PKG-DASH-03: [记录](changes/2026-09-12-PKG-DASH-03-runtime.md) [记录](baselines/dash-runtime.json) [记录](dash-validation.md)
|
||||
- PKG-DASH-04: [记录](changes/2026-09-12-PKG-DASH-04-types.md) [记录](baselines/dash-types-validation.json) [记录](dash-validation.md)
|
||||
@@ -1,5 +1,21 @@
|
||||
# 进度与证据
|
||||
|
||||
## 最新完成:DASH-04 严格 TS、公开类型和编辑器迁移
|
||||
|
||||
DASH 五个自有模块全部 TS 化,源码/公开工厂可互相赋值;默认字段和自定义 SDK 泛型准确,
|
||||
旧 object 回调、Parameters 配置提取、同步 update 与所有 JS 分发路径保持。
|
||||
补齐 CJS/ESM/legacy 类型桥和 Monaco 生成声明;实际 npm 旧声明与候选消费者对照通过。
|
||||
|
||||
全仓 261 个生产 TS 严格检查,完整 CI 715 项通过;源码 Node 116、三格式 Node 266 项通过。
|
||||
正式 main 三引擎 90 项(含核心/DASH Monaco 6 项)、legacy 84 项通过,无重试/跳过。
|
||||
工作区外 Yarn tarball 离线安装/冻结重装后五种类型模式通过,每模式拒绝八条非法用法。
|
||||
首次发现 tsconfig.json 泄露到包,已保留失败并修正 .npmignore,未手改生成产物。
|
||||
|
||||
DASH-TYPE-01 关闭;真实 dash.js/MPD/ABR、SDK 类型与设备/完整分发仍待验证。
|
||||
当前 217 项:74 done、3 doing、140 todo。下一步 DASH-05 进入真实 SDK 与媒体组合。
|
||||
详见 [本次变更](changes/2026-09-12-PKG-DASH-04-types.md) 和
|
||||
[执行证据](baselines/dash-types-validation.json)。独立本地提交,不推送/发布,全项目目标未完成。
|
||||
|
||||
## 最新完成:DASH-03 SDK 适配与生命周期源码改造
|
||||
|
||||
DASH 源码已拆为入口生命周期、SDK 适配、selector 模型、菜单所有权四个 JS 模块。
|
||||
|
||||
@@ -138,5 +138,5 @@
|
||||
| DASH-SDK-01 | open / 已复现 | npm 发布版 4.x 与工作区仅 5.x 的 SDK 接口不兼容 | PKG-DASH-02, PKG-DASH-03, PKG-DASH-05 |
|
||||
| DASH-LIFE-01 | resolved / 已复现 | DASH 空拓扑残留 UI,监听和旧选择回调缺乏关闭守卫 | PKG-DASH-02, PKG-DASH-03 |
|
||||
| DASH-STATE-01 | open / 已复现 | DASH 当前项高亮使用真值 ID、音轨身份和标签去重,边界待核实 | PKG-DASH-02, PKG-DASH-03, PKG-DASH-05 |
|
||||
| DASH-TYPE-01 | open / 源码/产物事实 | DASH 类型未表达默认工厂参数、SDK 回调对象和现代模块入口 | PKG-DASH-04 |
|
||||
| DASH-TYPE-01 | resolved / 源码/产物事实 | DASH 类型未表达默认工厂参数、SDK 回调对象和现代模块入口 | PKG-DASH-04 |
|
||||
| DASH-DEMO-01 | open / 源码/产物事实 | DASH 示例仅新 SDK 且重复安装会累积销毁回调 | PKG-DASH-06 |
|
||||
+15
-8
@@ -628,7 +628,7 @@
|
||||
"PKG-DASH-05"
|
||||
],
|
||||
"evidence": [
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"docs/assets/example/dash.control.js",
|
||||
"refactor/baselines/dash-control-contract.md"
|
||||
],
|
||||
@@ -2844,7 +2844,7 @@
|
||||
"evidence": [
|
||||
"refactor/baselines/dash-control-contract.md",
|
||||
"refactor/baselines/dash-control-release.json",
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts",
|
||||
"docs/assets/example/dash.control.js",
|
||||
"test/dash-contract.test.js",
|
||||
@@ -2867,7 +2867,7 @@
|
||||
"evidence": [
|
||||
"refactor/baselines/dash-control-contract.md",
|
||||
"refactor/baselines/dash-control-release.json",
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts",
|
||||
"docs/assets/example/dash.control.js",
|
||||
"test/dash-contract.test.js",
|
||||
@@ -2897,7 +2897,7 @@
|
||||
"evidence": [
|
||||
"refactor/baselines/dash-control-contract.md",
|
||||
"refactor/baselines/dash-control-release.json",
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts",
|
||||
"docs/assets/example/dash.control.js",
|
||||
"test/dash-contract.test.js",
|
||||
@@ -2912,19 +2912,26 @@
|
||||
"id": "DASH-TYPE-01",
|
||||
"title": "DASH 类型未表达默认工厂参数、SDK 回调对象和现代模块入口",
|
||||
"confirmation": "source-observed",
|
||||
"status": "open",
|
||||
"status": "resolved",
|
||||
"owners": [
|
||||
"PKG-DASH-04"
|
||||
],
|
||||
"evidence": [
|
||||
"refactor/baselines/dash-control-contract.md",
|
||||
"refactor/baselines/dash-control-release.json",
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts",
|
||||
"docs/assets/example/dash.control.js"
|
||||
],
|
||||
"compatibleResolution": "保留旧类型推断,提供准确的 SDK 适配/回调契约和兼容格式入口,不以 any 掩盖源码。",
|
||||
"closureCriteria": "严格源码、旧/新编译器消费者与隔离产物类型验证通过。"
|
||||
"closureCriteria": "严格源码、旧/新编译器消费者与隔离产物类型验证通过。",
|
||||
"resolutionEvidence": [
|
||||
"refactor/baselines/dash-types-validation.json",
|
||||
"refactor/changes/2026-09-12-PKG-DASH-04-types.md",
|
||||
"test/types/dash-control.ts",
|
||||
"refactor/scripts/dash-package-types.mjs"
|
||||
],
|
||||
"resolutionRationale": "五个自有 TS 模块严格检查通过,真实旧 npm 声明/候选消费者在 TS 4.3/5.9 兼容,五种模块模式及非法用法验证、真实 Monaco、工作区外 Yarn tarball 安装与类型检查通过。只关闭插件自身声明和格式解析问题,实际 SDK 类型/媒体矩阵仍由 05 接续。"
|
||||
},
|
||||
{
|
||||
"id": "DASH-DEMO-01",
|
||||
@@ -2937,7 +2944,7 @@
|
||||
"evidence": [
|
||||
"refactor/baselines/dash-control-contract.md",
|
||||
"refactor/baselines/dash-control-release.json",
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts",
|
||||
"docs/assets/example/dash.control.js"
|
||||
],
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import ts from 'typescript'
|
||||
import compat from 'typescript-compat'
|
||||
import { checkFiles, packedFiles } from '../../scripts/package-check.mjs'
|
||||
import { consumerDirectory, removeConsumer, run, workspace, writeJson } from '../../scripts/package-consumer.mjs'
|
||||
import { hash, readMember } from './releases.mjs'
|
||||
|
||||
async function main() {
|
||||
assert.equal(process.env.npm_config_user_agent?.split(' ')[0], 'yarn/1.22.22', 'Use yarn test:dash-types-package')
|
||||
const yarn = process.env.npm_execpath
|
||||
assert(yarn && fs.existsSync(yarn))
|
||||
const output = fs.mkdtempSync(path.join(workspace, 'refactor/.cache/dash-package-types-'))
|
||||
console.log(`DASH isolated package type evidence: ${output}`)
|
||||
const consumer = consumerDirectory()
|
||||
try {
|
||||
const packages = []
|
||||
const published = JSON.parse(fs.readFileSync(path.join(workspace, 'refactor/baselines/dash-control-release.json'))).release
|
||||
for (const name of ['artplayer', 'artplayer-plugin-dash-control']) {
|
||||
const archive = path.join(output, `${name}.tgz`)
|
||||
fs.writeFileSync(path.join(output, `${name}-pack.log`), run([yarn, 'pack', '--filename', archive], path.join(workspace, 'packages', name)))
|
||||
const files = packedFiles(archive)
|
||||
const manifest = JSON.parse(readMember(archive, 'package/package.json'))
|
||||
checkFiles(manifest, files, name === published.name ? Object.keys(published.files) : [])
|
||||
packages.push({ name, archive, sha256: hash(fs.readFileSync(archive)), files: Object.fromEntries(files.map(member => [member, hash(readMember(archive, member))])) })
|
||||
}
|
||||
writeJson(path.join(consumer, 'package.json'), { name: 'dash-isolated-type-consumer', private: true, dependencies: Object.fromEntries(packages.map(pkg => [pkg.name, `file:${pkg.archive.replaceAll('\\', '/')}`])) })
|
||||
fs.copyFileSync(path.join(workspace, 'yarn.lock'), path.join(consumer, 'yarn.lock'))
|
||||
fs.writeFileSync(path.join(output, 'install.log'), run([yarn, 'install', '--offline', '--ignore-scripts', '--non-interactive'], consumer))
|
||||
const lock = fs.readFileSync(path.join(consumer, 'yarn.lock'))
|
||||
fs.writeFileSync(path.join(output, 'frozen-install.log'), run([yarn, 'install', '--offline', '--frozen-lockfile', '--ignore-scripts', '--non-interactive'], consumer))
|
||||
assert.deepEqual(fs.readFileSync(path.join(consumer, 'yarn.lock')), lock)
|
||||
fs.writeFileSync(path.join(output, 'yarn.lock'), lock)
|
||||
for (const pkg of packages) {
|
||||
const root = path.join(consumer, 'node_modules', pkg.name)
|
||||
assert.equal(fs.realpathSync(root), root, 'Installed package is a workspace link')
|
||||
for (const [member, expected] of Object.entries(pkg.files))
|
||||
assert.equal(hash(fs.readFileSync(path.join(root, member.slice(8)))), expected, `Installed bytes differ: ${member}`)
|
||||
}
|
||||
const matrix = []
|
||||
for (const [compiler, mode] of [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']]) {
|
||||
const next = mode.startsWith('nodenext')
|
||||
const extension = next ? mode.endsWith('-cjs') ? 'cts' : 'mts' : 'ts'
|
||||
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: true, target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: next ? compiler.ModuleKind.NodeNext : mode === 'bundler-esm' ? compiler.ModuleKind.ESNext : compiler.ModuleKind.CommonJS, moduleResolution: next ? compiler.ModuleResolutionKind.NodeNext : mode === 'bundler-esm' ? compiler.ModuleResolutionKind.Bundler : compiler.ModuleResolutionKind.NodeJs }
|
||||
const source = fs.readFileSync(path.join(workspace, 'test/types/dash-control.ts'), 'utf8')
|
||||
const filename = path.join(consumer, `current.${extension}`)
|
||||
const legacy = path.join(consumer, `legacy.${extension}`)
|
||||
fs.copyFileSync(path.join(workspace, 'refactor/fixtures/consumers/dash-control-legacy.ts'), legacy)
|
||||
const files = [filename, legacy]
|
||||
if (mode === 'nodenext-cjs') {
|
||||
const commonjs = path.join(consumer, 'commonjs.cts')
|
||||
fs.writeFileSync(commonjs, `import dash = require('artplayer-plugin-dash-control'); import legacy = require('artplayer-plugin-dash-control/legacy');
|
||||
const option: dash.Option = { quality: { getName: level => String(level.height) } }; dash(option); legacy();`)
|
||||
files.push(commonjs)
|
||||
}
|
||||
function compile(code) {
|
||||
fs.writeFileSync(filename, code)
|
||||
const program = compiler.createProgram(files, options)
|
||||
for (const file of program.getSourceFiles()) {
|
||||
const actual = fs.realpathSync(file.fileName)
|
||||
assert(actual.startsWith(fs.realpathSync(consumer) + path.sep) || (program.isSourceFileDefaultLibrary(file) && path.dirname(actual) === fs.realpathSync(path.dirname(compiler.sys.getExecutingFilePath()))), `Types escaped isolated consumer: ${actual}`)
|
||||
}
|
||||
return compiler.getPreEmitDiagnostics(program).map(item => ({ code: item.code, message: compiler.flattenDiagnosticMessageText(item.messageText, '\n') }))
|
||||
}
|
||||
const diagnostics = compile(source)
|
||||
assert.deepEqual(diagnostics, [], `${compiler.version} ${mode}`)
|
||||
const invalid = compile(source.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, ''))
|
||||
assert.equal(invalid.length, 8, 'Installed package must reject all invalid uses')
|
||||
matrix.push({ compiler: compiler.version, mode, diagnostics, invalid })
|
||||
}
|
||||
const report = { task: 'PKG-DASH-04', scope: 'Packed current core and DASH, offline Yarn install and frozen reinstall outside workspace; isolated public type acceptance only, not complete package runtime/SDK/media release validation.', packages, matrix }
|
||||
writeJson(path.join(output, 'report.json'), report)
|
||||
console.log(`DASH installed type matrix passed: ${matrix.length} modes, eight invalid uses rejected in each; ${output}`)
|
||||
}
|
||||
finally {
|
||||
removeConsumer(consumer)
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error)
|
||||
process.exitCode = 1
|
||||
})
|
||||
@@ -0,0 +1,78 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
// eslint-disable-next-line test/no-import-node-test -- Run exact compiler and editor compatibility contracts.
|
||||
import test from 'node:test'
|
||||
import { ESLint } from 'eslint'
|
||||
import ts from 'typescript'
|
||||
import compat from 'typescript-compat'
|
||||
import { checkPluginEditorDeclaration, generatePluginEditorDeclaration } from '../../scripts/plugin-editor-types.mjs'
|
||||
import { checkConsumer } from '../../scripts/typecheck.mjs'
|
||||
import { ensureArchive, hash, readMember, refactorDir } from './releases.mjs'
|
||||
|
||||
test('DASH public factories preserve root/legacy imports, inferred SDK fields and historical extraction', () => {
|
||||
const source = fs.readFileSync('test/types/dash-control.ts', 'utf8')
|
||||
for (const [compiler, mode] of [[ts, 'node10-commonjs'], [ts, 'nodenext-cjs'], [ts, 'nodenext-esm'], [ts, 'bundler-esm'], [compat, 'node10-commonjs']]) {
|
||||
assert.deepEqual(checkConsumer(compiler, mode, source), [], `${compiler.version} ${mode}`)
|
||||
const invalid = source.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, '')
|
||||
assert.equal(checkConsumer(compiler, mode, invalid).length, 8, 'Every invalid use must remain invalid')
|
||||
}
|
||||
const commonjs = `import dash = require('artplayer-plugin-dash-control'); import legacy = require('artplayer-plugin-dash-control/legacy');
|
||||
const option: dash.Option = { quality: { getName: level => String(level.height) } }; dash(option); legacy();`
|
||||
assert.deepEqual(checkConsumer(ts, 'nodenext-cjs', commonjs), [])
|
||||
})
|
||||
|
||||
test('DASH legacy consumer compiles against the actual published declaration and candidate', async () => {
|
||||
const { release } = JSON.parse(fs.readFileSync(path.join(refactorDir, 'baselines/dash-control-release.json')))
|
||||
const member = 'package/types/artplayer-plugin-dash-control.d.ts'
|
||||
const bytes = readMember(await ensureArchive(release), member)
|
||||
assert.equal(hash(bytes), release.files[member])
|
||||
const source = fs.readFileSync(path.join(refactorDir, 'fixtures/consumers/dash-control-legacy.ts'), 'utf8')
|
||||
const directory = fs.mkdtempSync(path.join(refactorDir, '.cache/dash-legacy-types-'))
|
||||
try {
|
||||
const filename = path.join(directory, 'consumer.ts')
|
||||
fs.writeFileSync(path.join(directory, 'legacy.d.ts'), bytes)
|
||||
fs.writeFileSync(filename, source.replace('from \'artplayer-plugin-dash-control\'', 'from \'./legacy\''))
|
||||
for (const compiler of [ts, compat]) {
|
||||
const program = compiler.createProgram([filename], { strict: true, noEmit: true, skipLibCheck: false, types: [], esModuleInterop: true, module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs, target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'] })
|
||||
const diagnostics = compiler.getPreEmitDiagnostics(program).map(item => ({ code: item.code, message: compiler.flattenDiagnosticMessageText(item.messageText, '\n') }))
|
||||
assert.deepEqual(diagnostics, [], `Published / TS ${compiler.version}`)
|
||||
assert(program.getSourceFiles().some(file => path.resolve(file.fileName) === path.join(directory, 'legacy.d.ts')))
|
||||
assert.deepEqual(checkConsumer(compiler, 'node10-commonjs', source), [], `Candidate / TS ${compiler.version}`)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
const resolved = fs.realpathSync(directory)
|
||||
assert.equal(path.dirname(resolved), fs.realpathSync(path.join(refactorDir, '.cache')))
|
||||
assert(path.basename(resolved).startsWith('dash-legacy-types-'))
|
||||
fs.rmSync(resolved, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
test('DASH editor declarations are reproducible, standalone, precise and compatible with old TS', async () => {
|
||||
const source = fs.readFileSync('packages/artplayer-plugin-dash-control/types/artplayer-plugin-dash-control.d.ts', 'utf8')
|
||||
const generated = generatePluginEditorDeclaration(source, 'artplayerPluginDashControl')
|
||||
const file = 'docs/assets/ts/artplayer-plugin-dash-control.d.ts'
|
||||
const [formatted] = await new ESLint({ fix: true, fixTypes: ['layout'] }).lintText(generated, { filePath: file })
|
||||
assert.equal(formatted.errorCount, 0)
|
||||
assert.equal(fs.readFileSync(file, 'utf8').replaceAll('\r\n', '\n'), formatted.output || generated, 'Run yarn build:ts')
|
||||
const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8')
|
||||
const consumer = `
|
||||
const option: artplayerPluginDashControl.Option = { quality: { getName: level => String(level.height) }, audio: { getName: track => track.lang || String(track.id) } }
|
||||
const oldQuality: Parameters<typeof artplayerPluginDashControl>[0]['quality'] = { getName: (level: object) => String(level) }
|
||||
const factory: (art: Artplayer) => artplayerPluginDashControl.Result = artplayerPluginDashControl(option)
|
||||
artplayerPluginDashControl()
|
||||
artplayerPluginDashControl(undefined)
|
||||
// @ts-expect-error A formatter must return a string.
|
||||
artplayerPluginDashControl({ quality: { getName: level => level.height } })
|
||||
// @ts-expect-error SDK fields cannot become any.
|
||||
artplayerPluginDashControl({ audio: { getName: track => track.unknownProperty } })
|
||||
// @ts-expect-error Private definition namespace must not leak globally.
|
||||
const hidden: artplayerPluginDashControlDefinitions.Option = {}
|
||||
void [oldQuality, factory, hidden]
|
||||
`
|
||||
for (const compiler of [ts, compat]) {
|
||||
assert.deepEqual(checkPluginEditorDeclaration(generated, core, consumer, compiler), [], compiler.version)
|
||||
assert.equal(checkPluginEditorDeclaration(generated, core, consumer.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, ''), compiler).length, 3)
|
||||
}
|
||||
})
|
||||
+6
-2
@@ -2037,11 +2037,15 @@
|
||||
"ENG-06",
|
||||
"CORE-07"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "H",
|
||||
"deliverable": "dash.js adapter、selector 和回调类型",
|
||||
"acceptance": "严格类型检查、旧消费样例通过;声明路径/导出和同步异步兼容",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-12-PKG-DASH-04-types.md",
|
||||
"baselines/dash-types-validation.json",
|
||||
"dash-validation.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PKG-DASH-05",
|
||||
|
||||
@@ -1042,13 +1042,14 @@
|
||||
"riskId": "SDK-02",
|
||||
"owners": [
|
||||
"PKG-DASH-01",
|
||||
"PKG-DASH-05",
|
||||
"EX-03"
|
||||
],
|
||||
"sourceFiles": [
|
||||
"packages/artplayer-plugin-dash-control/src/index.js",
|
||||
"packages/artplayer-plugin-dash-control/src/index.ts",
|
||||
"docs/assets/example/dash.control.js"
|
||||
],
|
||||
"contract": "Caller owns art.dash. Published plugin 1.1.0 uses dash.js 4.x (demo 4.5.2); workspace uses 5.x (demo 5.2.1). Preserve both through capability adapters and v5 stable representation IDs; actual SDK playback remains PKG-DASH-05.",
|
||||
"contract": "Caller owns art.dash. Candidate adapts the released 4.x quality method surface and workspace 5.x stable representation ID surface. Controlled contracts and DOM validation pass; actual pinned 4.5.2/5.2.1 SDK media remains PKG-DASH-05.",
|
||||
"validationStatus": "Source integration observed; complete real SDK/service/device matrix not yet verified.",
|
||||
"demoPathsSource": "refactor/baselines/demo-inventory.json"
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user