mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 19:06:15 -08:00
refactor(docs): [SITE-02] generate and validate standalone editor types
This commit is contained in:
1 parent
1a5440a67f
commit
76499e7a3e
30 files changed
+2955
-459
No files matched your search
+21
-17
@@ -1,21 +1,25 @@
|
||||
export type Chapters = {
|
||||
start: number
|
||||
end: number
|
||||
title: string
|
||||
}[]
|
||||
|
||||
export interface Option {
|
||||
chapters?: Chapters
|
||||
// Generated from the package public declaration by yarn build:ts. Do not edit.
|
||||
/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */
|
||||
declare namespace artplayerPluginChapterDefinitions {
|
||||
export type Chapters = {
|
||||
start: number
|
||||
end: number
|
||||
title: string
|
||||
}[]
|
||||
export interface Option {
|
||||
chapters?: Chapters
|
||||
}
|
||||
export interface Result {
|
||||
name: 'artplayerPluginChapter'
|
||||
update: (option: Option) => void
|
||||
}
|
||||
export const artplayerPluginChapter: (option?: Option) => (art: Artplayer) => Result
|
||||
}
|
||||
|
||||
export interface Result {
|
||||
name: 'artplayerPluginChapter'
|
||||
update: (option: Option) => void
|
||||
declare const artplayerPluginChapter: typeof artplayerPluginChapterDefinitions.artplayerPluginChapter
|
||||
declare namespace artplayerPluginChapter {
|
||||
export type Chapters = artplayerPluginChapterDefinitions.Chapters
|
||||
export type Option = artplayerPluginChapterDefinitions.Option
|
||||
export type Result = artplayerPluginChapterDefinitions.Result
|
||||
}
|
||||
|
||||
declare const artplayerPluginChapter: (option?: Option) => (art: Artplayer) => Result
|
||||
|
||||
export default artplayerPluginChapter
|
||||
|
||||
export = artplayerPluginChapter
|
||||
export as namespace artplayerPluginChapter;
|
||||
@@ -0,0 +1,224 @@
|
||||
@glomex/vast-ima-player
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2020 glomex GmbH
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
@alugha/ima
|
||||
# The MIT License (MIT)
|
||||
|
||||
**Copyright 2020 Alugha GmbH**
|
||||
|
||||
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.
|
||||
+1390
-27
File diff suppressed because it is too large.
Load diff
+5
-4
@@ -40,14 +40,14 @@
|
||||
"test:dash-control": "node --test test/dash-control.test.js test/dash-contract.test.js test/dash-lifecycle.test.js test/dash-events.test.js",
|
||||
"dev": "npx cross-env NODE_ENV=development node ./scripts/dev.js",
|
||||
"build": "npx cross-env NODE_ENV=production node ./scripts/build.js",
|
||||
"lint": "eslint \"packages/*/{src,public,types,package.json}\" \"scripts/*.{js,mjs}\" \"scripts/docs-smoke/**/*.ts\" \"test/*\" \"docs/assets/ts/*\" \"types/*.d.ts\" \"playwright*.config.js\" --no-fix",
|
||||
"lint": "eslint \"packages/*/{src,public,types,package.json}\" \"scripts/*.{js,mjs}\" \"scripts/{docs-smoke,editor-declarations}/**/*.ts\" \"test/*\" \"docs/assets/ts/*\" \"types/*.d.ts\" \"playwright*.config.js\" --no-fix",
|
||||
"build:all": "yarn ci:build && yarn lint",
|
||||
"check:toolchain": "node scripts/check-toolchain.mjs",
|
||||
"lint:fix": "eslint \"packages/*/{src,public,types,package.json}\" \"scripts/*.{js,mjs}\" \"scripts/docs-smoke/**/*.ts\" \"test/*\" \"docs/assets/ts/*\" \"types/*.d.ts\" \"playwright*.config.js\" --fix",
|
||||
"lint:fix": "eslint \"packages/*/{src,public,types,package.json}\" \"scripts/*.{js,mjs}\" \"scripts/{docs-smoke,editor-declarations}/**/*.ts\" \"test/*\" \"docs/assets/ts/*\" \"types/*.d.ts\" \"playwright*.config.js\" --fix",
|
||||
"check:plan": "node refactor/scripts/plan.mjs --check",
|
||||
"test:node": "yarn test:unit && node --test test/toolchain.test.js test/build-docs.test.js test/package-check.test.js test/declarations.test.js test/editor-types.test.js test/coverage.test.js test/performance-report.test.js test/media-gate.test.js test/ci-summary.test.js test/package-runtime.test.js test/library-build.test.js",
|
||||
"test:baseline": "node --test refactor/scripts/*.test.mjs",
|
||||
"ci:check": "yarn check:toolchain --strict && yarn check:commits --report && yarn check:impact --report && yarn check:ci && yarn test:contracts && yarn check:contracts --report && yarn check:plan && yarn lint && yarn typecheck:docs-tools && yarn check:docs-smoke && yarn check:types && yarn typecheck && yarn typecheck:react && yarn lint:react && yarn typecheck:vue && yarn lint:vue && yarn test",
|
||||
"ci:check": "yarn check:toolchain --strict && yarn check:commits --report && yarn check:impact --report && yarn check:ci && yarn test:contracts && yarn check:contracts --report && yarn check:plan && yarn lint && yarn typecheck:docs-tools && yarn check:docs-smoke && yarn check:editor-types && yarn check:types && yarn typecheck && yarn typecheck:react && yarn lint:react && yarn typecheck:vue && yarn lint:vue && yarn test",
|
||||
"ci:build": "yarn build:types && yarn build all && yarn build:i18n && yarn build:ts && yarn build:test && yarn build:docs && yarn test:imports",
|
||||
"test:imports": "node --test test/esm.test.js test/i18n.test.js test/ssr.test.js test/asr-distribution.test.js",
|
||||
"typecheck": "node scripts/typecheck.mjs",
|
||||
@@ -120,7 +120,8 @@
|
||||
"test:vue-consumer": "node refactor/scripts/vue-consumer.mjs",
|
||||
"lint:vue": "eslint example/vue.js --no-fix",
|
||||
"typecheck:docs-tools": "node node_modules/typescript/bin/tsc -p scripts/tsconfig.docs.json --noEmit",
|
||||
"check:docs-smoke": "node scripts/build-test.js --check"
|
||||
"check:docs-smoke": "node scripts/build-test.js --check",
|
||||
"check:editor-types": "node scripts/build-ts.js --check"
|
||||
},
|
||||
"browserslist": "last 1 Chrome version",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -42,6 +42,9 @@ The repository generators have different ownership:
|
||||
|
||||
- `scripts/build-types.mjs`: core public declaration sources to existing `types/`.
|
||||
- `scripts/build-ts.js`: standalone editor declarations and the editor library list.
|
||||
Checked TS modules in `scripts/editor-declarations/` validate all selected
|
||||
declarations together with current and historical compilers before writing.
|
||||
Use `yarn check:editor-types` for drift checks; see that module's README.
|
||||
- `scripts/build-test.js`: extracts Chinese Run Code blocks into `docs/test/test.js`.
|
||||
The TS implementation in `scripts/docs-smoke/` produces deterministic readiness
|
||||
smoke cases with owned frames, error observation and cleanup. It does not prove
|
||||
|
||||
@@ -0,0 +1,444 @@
|
||||
{
|
||||
"task": "SITE-02",
|
||||
"baseline": "1a5440a67f50c8c1c5c695099bea5ee5d4b0cc77",
|
||||
"node": "24.21.0",
|
||||
"yarn": "1.22.22",
|
||||
"compilers": [
|
||||
"5.9.3",
|
||||
"4.3.5"
|
||||
],
|
||||
"scope": {
|
||||
"generatedDeclarations": 22,
|
||||
"changedDeclarations": [
|
||||
"docs/assets/ts/artplayer-plugin-chapter.d.ts",
|
||||
"docs/assets/ts/artplayer-plugin-vast.d.ts"
|
||||
],
|
||||
"unchangedDeclarations": 20,
|
||||
"totalOutputs": 24,
|
||||
"rootLintExistingWarnings": 1,
|
||||
"packageRuntimeChanged": false,
|
||||
"packagePublicTypesChanged": false,
|
||||
"lockUnchanged": true
|
||||
},
|
||||
"logs": {
|
||||
"reproduction": {
|
||||
"file": "refactor/.cache/editor-before.log",
|
||||
"sha256": "13639bee172bc86c2b8787f325fa251be989c16c1bbf00a0a77636fe591da7fc"
|
||||
},
|
||||
"targeted": {
|
||||
"file": "refactor/.cache/editor-tests-final.log",
|
||||
"sha256": "bdcc879dc19dc25a086442c982f7e9fa091ec011d80e7878dfa9bab222733f85",
|
||||
"exitCode": 0,
|
||||
"pass": 4
|
||||
},
|
||||
"baseline": {
|
||||
"file": "refactor/.cache/editor-baseline.log",
|
||||
"sha256": "c92fcf9cfe1c64dfecb23d44bb37542519b78f7da4318b1c80322a81948949f4",
|
||||
"exitCode": 0,
|
||||
"pass": 522
|
||||
},
|
||||
"browserBefore": {
|
||||
"file": "refactor/.cache/editor-browser.log",
|
||||
"sha256": "07ed1bbb4fdc0ba2f45e8ef659ad8d73bbb1a6ffb1cfee0c212f7bc4829996a3",
|
||||
"exitCode": 1,
|
||||
"pass": 0
|
||||
},
|
||||
"browserAccepted": {
|
||||
"file": "refactor/.cache/editor-browser-verified.log",
|
||||
"sha256": "72784c4ce8f6ce298abc93529d1c2d2dfde1bb4bc582ed889b02ba27ab856b93",
|
||||
"exitCode": 0,
|
||||
"pass": 3
|
||||
},
|
||||
"buildAll": {
|
||||
"file": "refactor/.cache/editor-all-build.log",
|
||||
"sha256": "b3c6a01e75ce9e33ac43e63d90a79c5b3924294985d054ba1ef267b8ab683baf",
|
||||
"exitCode": 0
|
||||
},
|
||||
"readonlyCheck": {
|
||||
"file": "refactor/.cache/editor-readonly-check.log",
|
||||
"sha256": "91e7a45d96d8a86b96d49822ee6284e70e9c4577cc7ac8bc730fbfd2087b3517",
|
||||
"exitCode": 0
|
||||
},
|
||||
"typecheckTools": {
|
||||
"file": "refactor/.cache/editor-types-check.log",
|
||||
"sha256": "713f8f9c2ea18e5da3e50f5e3a943515b4e93e7adb8172025ee31a7d7b566cff",
|
||||
"exitCode": 0
|
||||
},
|
||||
"rootLint": {
|
||||
"file": "refactor/.cache/editor-root-lint.log",
|
||||
"sha256": "5d7ca80241e65fed23117d779a3e1fba0b2281003a304005ea014a0e3cb75cdf",
|
||||
"exitCode": 0
|
||||
},
|
||||
"targetedLint": {
|
||||
"file": "refactor/.cache/editor-final-lint.log",
|
||||
"sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
|
||||
"exitCode": 0
|
||||
},
|
||||
"ci": {
|
||||
"file": "refactor/.cache/editor-ci-tests.log",
|
||||
"sha256": "ebc514dfc48afff766aeba32c689a922efa36e8c85fc5d2552ca36f22248c0e5",
|
||||
"exitCode": 0,
|
||||
"pass": 50
|
||||
},
|
||||
"strictToolchainBefore": {
|
||||
"file": "refactor/.cache/editor-toolchain-direct-before.log",
|
||||
"sha256": "23de6d33eafd3123528d9a4f7b3d82131a32ee90e0724eaab8f2446bca9b48da",
|
||||
"exitCode": 1
|
||||
},
|
||||
"strictToolchain": {
|
||||
"file": "refactor/.cache/editor-toolchain.log",
|
||||
"sha256": "3da883e18990c25a4eee9f46febb386fc33b0ea6a25ff748d5c129bb8d16ea85",
|
||||
"exitCode": 0
|
||||
}
|
||||
},
|
||||
"browser": {
|
||||
"file": "refactor/.cache/editor-browser-accepted/report.json",
|
||||
"sha256": "20de4582ac416faa3e69d7a1444018a99e7ba0f00f60a114c5905cee5fdf6ff7",
|
||||
"stats": {
|
||||
"startTime": "2026-09-13T23:16:22.090Z",
|
||||
"duration": 23649.482000000004,
|
||||
"expected": 3,
|
||||
"skipped": 0,
|
||||
"unexpected": 0,
|
||||
"flaky": 0
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"title": "Monaco checks all editor declarations together and runs the Chapter consumer",
|
||||
"project": "chromium",
|
||||
"status": "expected",
|
||||
"attempts": 1,
|
||||
"browser": "153.0.8010.12",
|
||||
"platform": "win32",
|
||||
"errors": [],
|
||||
"result": {
|
||||
"syntax": [],
|
||||
"semantic": [],
|
||||
"declarations": [],
|
||||
"bad": [
|
||||
2322,
|
||||
2322,
|
||||
2322
|
||||
],
|
||||
"name": "artplayerPluginChapter",
|
||||
"ready": true,
|
||||
"instances": 0
|
||||
},
|
||||
"declarationInputs": {
|
||||
"artplayer-plugin-ads.d.ts": "bf128828d5b104fc844a4f134a02162e57472d8c927a50df7b3878f4c5ed7652",
|
||||
"artplayer-plugin-ambilight.d.ts": "9f06ccb7398053dca642ca369aa47f54cbb3e4dd4d5e252e999e59e496d8eee8",
|
||||
"artplayer-plugin-asr.d.ts": "5096f097636c018bc05c497324c271af3fefaebccda7fa3e9cd43b63477704ad",
|
||||
"artplayer-plugin-audio-track.d.ts": "604af2a3790eb7c583ba150c402dca0a3e458469cc74913b51fee2f3d3882541",
|
||||
"artplayer-plugin-auto-thumbnail.d.ts": "f66bba7f633202c2ef359a989269c643b75d91594364f7ed6fb67f9898aeac03",
|
||||
"artplayer-plugin-chapter.d.ts": "d5bd68579659afa44158c894e12372cedd6f958415ced370a65c294550aa828d",
|
||||
"artplayer-plugin-chromecast.d.ts": "0a0b932081cac0efbcedea28dc1077484963b7f406808378704062661a4c0338",
|
||||
"artplayer-plugin-danmuku-mask.d.ts": "06c6e938876edcc0ac2c8dcd1e1be4596b0f056685a3523d4c9836f2f2f90362",
|
||||
"artplayer-plugin-danmuku.d.ts": "e3421bdbdfc6bea1b0b633300350fff1a745d8bc21c1430b6154a23fa3ad0415",
|
||||
"artplayer-plugin-dash-control.d.ts": "c7e3c83f3377b615e503a270af12915dcc82fe3f2cfabdae396632855a27f73f",
|
||||
"artplayer-plugin-document-pip.d.ts": "42faa0a6549149efd01b46c3c59246bd4dc33f2383b63b04e9f5376de29fdb8e",
|
||||
"artplayer-plugin-hls-control.d.ts": "6a623bb6ba4cc0598a3dd1aab5ef7ca4fbae11973a787885eccba10cc7aa2c7c",
|
||||
"artplayer-plugin-jassub.d.ts": "ce713e0a61a81bfc31087ea1a880a99398ef7c2b833e567c91e4e98f5ae6f621",
|
||||
"artplayer-plugin-multiple-subtitles.d.ts": "edb15207df69a695311e849555cf989bfc32da20c2456731b6814de5400567bb",
|
||||
"artplayer-plugin-vast.d.ts": "b21ed9a852b3ec3cc9b409cce08e91905e42abdc1d642acc9b412c33c83287b7",
|
||||
"artplayer-plugin-vtt-thumbnail.d.ts": "d82c0fe08bcf9c60e2a634e9f1fd8ccc75dc8e0ddbfa8262cccaefc9604aa61b",
|
||||
"artplayer-proxy-canvas.d.ts": "83c408e0724a598f9ff32d68d752f39e03feb69ba4f6a49ba02f9d4df898453e",
|
||||
"artplayer-proxy-mediabunny.d.ts": "acbaa0a25f20ac15b3d79db00b3a16167f84452ab58933110f42dcb3262fbd3e",
|
||||
"artplayer-tool-iframe.d.ts": "c06c6819146ba64bd6ee498871d9e19ab5a9e88c9cc7bed2c0c4968fa39dfed7",
|
||||
"artplayer-tool-thumbnail.d.ts": "9b72d10a1fe964d54fcf4774770074058ea739b4f734b52b8f4adebb37fc83e6",
|
||||
"artplayer.d.ts": "652c0fdf605e87203526777a05851bd69c95c1660d5ff29eab19c00967c9a985",
|
||||
"artplayer-i18n.d.ts": "60851e22ea50ed540f1be0f5a110077cdd5e6ab87345a675838f6c6333517405"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Monaco checks all editor declarations together and runs the Chapter consumer",
|
||||
"project": "firefox",
|
||||
"status": "expected",
|
||||
"attempts": 1,
|
||||
"browser": "155.0",
|
||||
"platform": "win32",
|
||||
"errors": [],
|
||||
"result": {
|
||||
"syntax": [],
|
||||
"semantic": [],
|
||||
"declarations": [],
|
||||
"bad": [
|
||||
2322,
|
||||
2322,
|
||||
2322
|
||||
],
|
||||
"name": "artplayerPluginChapter",
|
||||
"ready": true,
|
||||
"instances": 0
|
||||
},
|
||||
"declarationInputs": {
|
||||
"artplayer-plugin-ads.d.ts": "bf128828d5b104fc844a4f134a02162e57472d8c927a50df7b3878f4c5ed7652",
|
||||
"artplayer-plugin-ambilight.d.ts": "9f06ccb7398053dca642ca369aa47f54cbb3e4dd4d5e252e999e59e496d8eee8",
|
||||
"artplayer-plugin-asr.d.ts": "5096f097636c018bc05c497324c271af3fefaebccda7fa3e9cd43b63477704ad",
|
||||
"artplayer-plugin-audio-track.d.ts": "604af2a3790eb7c583ba150c402dca0a3e458469cc74913b51fee2f3d3882541",
|
||||
"artplayer-plugin-auto-thumbnail.d.ts": "f66bba7f633202c2ef359a989269c643b75d91594364f7ed6fb67f9898aeac03",
|
||||
"artplayer-plugin-chapter.d.ts": "d5bd68579659afa44158c894e12372cedd6f958415ced370a65c294550aa828d",
|
||||
"artplayer-plugin-chromecast.d.ts": "0a0b932081cac0efbcedea28dc1077484963b7f406808378704062661a4c0338",
|
||||
"artplayer-plugin-danmuku-mask.d.ts": "06c6e938876edcc0ac2c8dcd1e1be4596b0f056685a3523d4c9836f2f2f90362",
|
||||
"artplayer-plugin-danmuku.d.ts": "e3421bdbdfc6bea1b0b633300350fff1a745d8bc21c1430b6154a23fa3ad0415",
|
||||
"artplayer-plugin-dash-control.d.ts": "c7e3c83f3377b615e503a270af12915dcc82fe3f2cfabdae396632855a27f73f",
|
||||
"artplayer-plugin-document-pip.d.ts": "42faa0a6549149efd01b46c3c59246bd4dc33f2383b63b04e9f5376de29fdb8e",
|
||||
"artplayer-plugin-hls-control.d.ts": "6a623bb6ba4cc0598a3dd1aab5ef7ca4fbae11973a787885eccba10cc7aa2c7c",
|
||||
"artplayer-plugin-jassub.d.ts": "ce713e0a61a81bfc31087ea1a880a99398ef7c2b833e567c91e4e98f5ae6f621",
|
||||
"artplayer-plugin-multiple-subtitles.d.ts": "edb15207df69a695311e849555cf989bfc32da20c2456731b6814de5400567bb",
|
||||
"artplayer-plugin-vast.d.ts": "b21ed9a852b3ec3cc9b409cce08e91905e42abdc1d642acc9b412c33c83287b7",
|
||||
"artplayer-plugin-vtt-thumbnail.d.ts": "d82c0fe08bcf9c60e2a634e9f1fd8ccc75dc8e0ddbfa8262cccaefc9604aa61b",
|
||||
"artplayer-proxy-canvas.d.ts": "83c408e0724a598f9ff32d68d752f39e03feb69ba4f6a49ba02f9d4df898453e",
|
||||
"artplayer-proxy-mediabunny.d.ts": "acbaa0a25f20ac15b3d79db00b3a16167f84452ab58933110f42dcb3262fbd3e",
|
||||
"artplayer-tool-iframe.d.ts": "c06c6819146ba64bd6ee498871d9e19ab5a9e88c9cc7bed2c0c4968fa39dfed7",
|
||||
"artplayer-tool-thumbnail.d.ts": "9b72d10a1fe964d54fcf4774770074058ea739b4f734b52b8f4adebb37fc83e6",
|
||||
"artplayer.d.ts": "652c0fdf605e87203526777a05851bd69c95c1660d5ff29eab19c00967c9a985",
|
||||
"artplayer-i18n.d.ts": "60851e22ea50ed540f1be0f5a110077cdd5e6ab87345a675838f6c6333517405"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Monaco checks all editor declarations together and runs the Chapter consumer",
|
||||
"project": "webkit",
|
||||
"status": "expected",
|
||||
"attempts": 1,
|
||||
"browser": "26.6",
|
||||
"platform": "win32",
|
||||
"errors": [],
|
||||
"result": {
|
||||
"syntax": [],
|
||||
"semantic": [],
|
||||
"declarations": [],
|
||||
"bad": [
|
||||
2322,
|
||||
2322,
|
||||
2322
|
||||
],
|
||||
"name": "artplayerPluginChapter",
|
||||
"ready": true,
|
||||
"instances": 0
|
||||
},
|
||||
"declarationInputs": {
|
||||
"artplayer-plugin-ads.d.ts": "bf128828d5b104fc844a4f134a02162e57472d8c927a50df7b3878f4c5ed7652",
|
||||
"artplayer-plugin-ambilight.d.ts": "9f06ccb7398053dca642ca369aa47f54cbb3e4dd4d5e252e999e59e496d8eee8",
|
||||
"artplayer-plugin-asr.d.ts": "5096f097636c018bc05c497324c271af3fefaebccda7fa3e9cd43b63477704ad",
|
||||
"artplayer-plugin-audio-track.d.ts": "604af2a3790eb7c583ba150c402dca0a3e458469cc74913b51fee2f3d3882541",
|
||||
"artplayer-plugin-auto-thumbnail.d.ts": "f66bba7f633202c2ef359a989269c643b75d91594364f7ed6fb67f9898aeac03",
|
||||
"artplayer-plugin-chapter.d.ts": "d5bd68579659afa44158c894e12372cedd6f958415ced370a65c294550aa828d",
|
||||
"artplayer-plugin-chromecast.d.ts": "0a0b932081cac0efbcedea28dc1077484963b7f406808378704062661a4c0338",
|
||||
"artplayer-plugin-danmuku-mask.d.ts": "06c6e938876edcc0ac2c8dcd1e1be4596b0f056685a3523d4c9836f2f2f90362",
|
||||
"artplayer-plugin-danmuku.d.ts": "e3421bdbdfc6bea1b0b633300350fff1a745d8bc21c1430b6154a23fa3ad0415",
|
||||
"artplayer-plugin-dash-control.d.ts": "c7e3c83f3377b615e503a270af12915dcc82fe3f2cfabdae396632855a27f73f",
|
||||
"artplayer-plugin-document-pip.d.ts": "42faa0a6549149efd01b46c3c59246bd4dc33f2383b63b04e9f5376de29fdb8e",
|
||||
"artplayer-plugin-hls-control.d.ts": "6a623bb6ba4cc0598a3dd1aab5ef7ca4fbae11973a787885eccba10cc7aa2c7c",
|
||||
"artplayer-plugin-jassub.d.ts": "ce713e0a61a81bfc31087ea1a880a99398ef7c2b833e567c91e4e98f5ae6f621",
|
||||
"artplayer-plugin-multiple-subtitles.d.ts": "edb15207df69a695311e849555cf989bfc32da20c2456731b6814de5400567bb",
|
||||
"artplayer-plugin-vast.d.ts": "b21ed9a852b3ec3cc9b409cce08e91905e42abdc1d642acc9b412c33c83287b7",
|
||||
"artplayer-plugin-vtt-thumbnail.d.ts": "d82c0fe08bcf9c60e2a634e9f1fd8ccc75dc8e0ddbfa8262cccaefc9604aa61b",
|
||||
"artplayer-proxy-canvas.d.ts": "83c408e0724a598f9ff32d68d752f39e03feb69ba4f6a49ba02f9d4df898453e",
|
||||
"artplayer-proxy-mediabunny.d.ts": "acbaa0a25f20ac15b3d79db00b3a16167f84452ab58933110f42dcb3262fbd3e",
|
||||
"artplayer-tool-iframe.d.ts": "c06c6819146ba64bd6ee498871d9e19ab5a9e88c9cc7bed2c0c4968fa39dfed7",
|
||||
"artplayer-tool-thumbnail.d.ts": "9b72d10a1fe964d54fcf4774770074058ea739b4f734b52b8f4adebb37fc83e6",
|
||||
"artplayer.d.ts": "652c0fdf605e87203526777a05851bd69c95c1660d5ff29eab19c00967c9a985",
|
||||
"artplayer-i18n.d.ts": "60851e22ea50ed540f1be0f5a110077cdd5e6ab87345a675838f6c6333517405"
|
||||
}
|
||||
}
|
||||
],
|
||||
"beforeArchive": "refactor/.cache/editor-browser-before",
|
||||
"beforeReason": "Directory has 23 .d.ts assets; actual libUris references 22, excluding historical WebSR. Browser test now follows actual loader list."
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"file": "scripts/build-ts.js",
|
||||
"sha256Lf": "1ff2d13f4247bba1818a187eb945a86969f4c4d60245ba5cac8fc0b2b8edd3ba"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-types.mjs",
|
||||
"sha256Lf": "62c6ef8affb5f28b9a9caa9810e3c5e565ca0d25fb031fe0a169beba6a3a1125"
|
||||
},
|
||||
{
|
||||
"file": "scripts/plugin-editor-types.mjs",
|
||||
"sha256Lf": "09b6bdc419e92d6052ba8575aa9b726e7231ca2579578cd91f9b34d1f99b44bc"
|
||||
},
|
||||
{
|
||||
"file": "scripts/tsconfig.docs.json",
|
||||
"sha256Lf": "4398157a60f8be091484d332455745708b999753cad3d7e0dd4a216c818da79e"
|
||||
},
|
||||
{
|
||||
"file": "scripts/tsconfig.editor.json",
|
||||
"sha256Lf": "ce57cedc75093d62f9d62efe1ff24c1d5d0fd157cbe830d082b8cebcf5f0e6a1"
|
||||
},
|
||||
{
|
||||
"file": "package.json",
|
||||
"sha256Lf": "0726e24a97b8107dd7c8effe37202b194d4211a3f06ea9c8c22058029a6d0871"
|
||||
},
|
||||
{
|
||||
"file": "test/editor-types.test.js",
|
||||
"sha256Lf": "2c431f49ca5b7428171ee7f494b48ac72df787c9a0824362855c49fc0c4cdbca"
|
||||
},
|
||||
{
|
||||
"file": "test/browser/editor-declarations.spec.js",
|
||||
"sha256Lf": "33e824e96b2fb385fa99fd384325f9cf660c49eff0afd4fb0234a3a5f4048e00"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/core.ts",
|
||||
"sha256Lf": "0cda0fe093299099c62ae907a6f517f1cb5c49be9085d4c8fb20aed6579a0058"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/dependencies.ts",
|
||||
"sha256Lf": "aa697e095f3e9ea476a2ae625714542f62db47e1257cb69cc5e249277db67f8c"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/generate.ts",
|
||||
"sha256Lf": "6cf6ee27b2032e9e3a4aef949f2b54ba7bf12e40bed473478f63eb82759c8e5a"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/plugin.ts",
|
||||
"sha256Lf": "02dd90a19b75235ac6080aa2088114f3ae51c45567789c7daf2653be63ceee7d"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/README.md",
|
||||
"sha256Lf": "968b7d6b558a5dde76bc004517fa02eaa33d81a1051e34b33f21a112d85aa8a0"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/syntax.ts",
|
||||
"sha256Lf": "d5c7d8f400b3053e1c1a588dab809f5d17e95be88ecb985cbc90f9ffaea3a0e6"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/validation.ts",
|
||||
"sha256Lf": "1b5524844d030ba32df8bb47f1f3963e7df1f0843db61ad1cc7a983db2546517"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/vast-sdk.ts",
|
||||
"sha256Lf": "6da9176284b7a697a922b90befa64263e016f12eef483793cc524bdfc028ad05"
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-i18n.d.ts",
|
||||
"sha256Lf": "60851e22ea50ed540f1be0f5a110077cdd5e6ab87345a675838f6c6333517405"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-ads.d.ts",
|
||||
"sha256Lf": "bf128828d5b104fc844a4f134a02162e57472d8c927a50df7b3878f4c5ed7652"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-ambilight.d.ts",
|
||||
"sha256Lf": "9f06ccb7398053dca642ca369aa47f54cbb3e4dd4d5e252e999e59e496d8eee8"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-asr.d.ts",
|
||||
"sha256Lf": "5096f097636c018bc05c497324c271af3fefaebccda7fa3e9cd43b63477704ad"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-audio-track.d.ts",
|
||||
"sha256Lf": "604af2a3790eb7c583ba150c402dca0a3e458469cc74913b51fee2f3d3882541"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-auto-thumbnail.d.ts",
|
||||
"sha256Lf": "f66bba7f633202c2ef359a989269c643b75d91594364f7ed6fb67f9898aeac03"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-chapter.d.ts",
|
||||
"sha256Lf": "d5bd68579659afa44158c894e12372cedd6f958415ced370a65c294550aa828d"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-chromecast.d.ts",
|
||||
"sha256Lf": "0a0b932081cac0efbcedea28dc1077484963b7f406808378704062661a4c0338"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-danmuku-mask.d.ts",
|
||||
"sha256Lf": "06c6e938876edcc0ac2c8dcd1e1be4596b0f056685a3523d4c9836f2f2f90362"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-danmuku.d.ts",
|
||||
"sha256Lf": "e3421bdbdfc6bea1b0b633300350fff1a745d8bc21c1430b6154a23fa3ad0415"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-dash-control.d.ts",
|
||||
"sha256Lf": "c7e3c83f3377b615e503a270af12915dcc82fe3f2cfabdae396632855a27f73f"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-document-pip.d.ts",
|
||||
"sha256Lf": "42faa0a6549149efd01b46c3c59246bd4dc33f2383b63b04e9f5376de29fdb8e"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-hls-control.d.ts",
|
||||
"sha256Lf": "6a623bb6ba4cc0598a3dd1aab5ef7ca4fbae11973a787885eccba10cc7aa2c7c"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-jassub.d.ts",
|
||||
"sha256Lf": "ce713e0a61a81bfc31087ea1a880a99398ef7c2b833e567c91e4e98f5ae6f621"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-multiple-subtitles.d.ts",
|
||||
"sha256Lf": "edb15207df69a695311e849555cf989bfc32da20c2456731b6814de5400567bb"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-vast.d.ts",
|
||||
"sha256Lf": "b21ed9a852b3ec3cc9b409cce08e91905e42abdc1d642acc9b412c33c83287b7"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-vtt-thumbnail.d.ts",
|
||||
"sha256Lf": "d82c0fe08bcf9c60e2a634e9f1fd8ccc75dc8e0ddbfa8262cccaefc9604aa61b"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-proxy-canvas.d.ts",
|
||||
"sha256Lf": "83c408e0724a598f9ff32d68d752f39e03feb69ba4f6a49ba02f9d4df898453e"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-proxy-mediabunny.d.ts",
|
||||
"sha256Lf": "acbaa0a25f20ac15b3d79db00b3a16167f84452ab58933110f42dcb3262fbd3e"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-tool-iframe.d.ts",
|
||||
"sha256Lf": "c06c6819146ba64bd6ee498871d9e19ab5a9e88c9cc7bed2c0c4968fa39dfed7"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-tool-thumbnail.d.ts",
|
||||
"sha256Lf": "9b72d10a1fe964d54fcf4774770074058ea739b4f734b52b8f4adebb37fc83e6"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer.d.ts",
|
||||
"sha256Lf": "652c0fdf605e87203526777a05851bd69c95c1660d5ff29eab19c00967c9a985"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/js/common.js",
|
||||
"sha256Lf": "cc9f7d780cf4f0ffb9aaee75da69e2b2b062f3bac07b4ffc9a75956b2e7cd7af"
|
||||
},
|
||||
{
|
||||
"file": "docs/assets/ts/artplayer-plugin-vast.LICENSE.txt",
|
||||
"sha256Lf": "967db6e5026a2fd3cc24d8a04e5c78859f543d0c0f6d4f9599c103e4e93c9b29"
|
||||
}
|
||||
],
|
||||
"sdk": [
|
||||
{
|
||||
"name": "@glomex/vast-ima-player",
|
||||
"version": "1.21.2",
|
||||
"manifest": {
|
||||
"file": "node_modules\\@glomex\\vast-ima-player\\package.json",
|
||||
"sha256": "c7361321ce792f6830af9eb40e70b7508a75f68290a3c0077e26a6f36daa7097"
|
||||
},
|
||||
"license": {
|
||||
"file": "node_modules\\@glomex\\vast-ima-player\\LICENSE",
|
||||
"sha256": "68b35bb64e6269277318ff4e4ee66a738bdeb83bbcdc7e3c3af85a0bdded8d0b"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "@alugha/ima",
|
||||
"version": "2.1.0",
|
||||
"manifest": {
|
||||
"file": "node_modules\\@alugha\\ima\\package.json",
|
||||
"sha256": "0c0f9d2a4cc8ea3f96239b44e4ef764630421998e5de91d05d04e42582b24852"
|
||||
},
|
||||
"license": {
|
||||
"file": "node_modules\\@alugha\\ima\\LICENSE.md",
|
||||
"sha256": "0fe0f6dd9671aecf84ea082cdcd7b3297b75ca942d082b485b94dd3b4dfd648a"
|
||||
}
|
||||
}
|
||||
],
|
||||
"limitations": [
|
||||
"Browser uses repository Monaco, not an entire editor UI/route acceptance.",
|
||||
"VAST is type-only; no ad SDK request, no runtime default behavior decision.",
|
||||
"No full production/runtime or publication matrix rerun, no remote CI or manual Chrome/iab.",
|
||||
"No new dependencies, push or publication."
|
||||
]
|
||||
}
|
||||
@@ -18101,15 +18101,15 @@
|
||||
},
|
||||
{
|
||||
"file": "scripts/build-ts.js",
|
||||
"sha256Lf": "338f3b5b4e4bdcb42c878997d13da6f71ce9842d730f57efece7566124dae9f6"
|
||||
"sha256Lf": "1ff2d13f4247bba1818a187eb945a86969f4c4d60245ba5cac8fc0b2b8edd3ba"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-types.mjs",
|
||||
"sha256Lf": "951d3d40dc7f90034561fd1a3b3015bdb1449593121bb410e3f15e4415547b8b"
|
||||
"sha256Lf": "62c6ef8affb5f28b9a9caa9810e3c5e565ca0d25fb031fe0a169beba6a3a1125"
|
||||
},
|
||||
{
|
||||
"file": "scripts/plugin-editor-types.mjs",
|
||||
"sha256Lf": "429c304ce7c801836a311e76e85f2e6dc0328d599103e39d071a915164b94102"
|
||||
"sha256Lf": "09b6bdc419e92d6052ba8575aa9b726e7231ca2579578cd91f9b34d1f99b44bc"
|
||||
},
|
||||
{
|
||||
"file": "scripts/build-test.js",
|
||||
@@ -18166,6 +18166,34 @@
|
||||
{
|
||||
"file": "scripts/docs-smoke/runtime.ts",
|
||||
"sha256Lf": "9fae3aa1bc6a6ef9728d9a677de9e283d40314022b710b2ecf19a9b951f6291d"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/core.ts",
|
||||
"sha256Lf": "0cda0fe093299099c62ae907a6f517f1cb5c49be9085d4c8fb20aed6579a0058"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/dependencies.ts",
|
||||
"sha256Lf": "aa697e095f3e9ea476a2ae625714542f62db47e1257cb69cc5e249277db67f8c"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/generate.ts",
|
||||
"sha256Lf": "6cf6ee27b2032e9e3a4aef949f2b54ba7bf12e40bed473478f63eb82759c8e5a"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/plugin.ts",
|
||||
"sha256Lf": "02dd90a19b75235ac6080aa2088114f3ae51c45567789c7daf2653be63ceee7d"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/syntax.ts",
|
||||
"sha256Lf": "d5c7d8f400b3053e1c1a588dab809f5d17e95be88ecb985cbc90f9ffaea3a0e6"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/validation.ts",
|
||||
"sha256Lf": "1b5524844d030ba32df8bb47f1f3963e7df1f0843db61ad1cc7a983db2546517"
|
||||
},
|
||||
{
|
||||
"file": "scripts/editor-declarations/vast-sdk.ts",
|
||||
"sha256Lf": "6da9176284b7a697a922b90befa64263e016f12eef483793cc524bdfc028ad05"
|
||||
}
|
||||
],
|
||||
"generationCommands": {
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
# SITE-02 编辑器声明生成链
|
||||
|
||||
起点 `1a5440a67f50c8c1c5c695099bea5ee5d4b0cc77`。SITE-SMOKE-01 已完成示例
|
||||
生成半项,本次完成声明生成半项,保留全部父任务范围。原 build:ts 命令、按包
|
||||
参数、声明 URL、i18n 入口和工具 MJS 导入路径继续可用。生产包源码、公开声明、
|
||||
运行时事件/DOM、分发入口与 yarn.lock 未修改。
|
||||
|
||||
## 结构与修复
|
||||
|
||||
- `scripts/editor-declarations/` 包含 TS 的 core/plugin AST 转换、语法检查、
|
||||
VAST SDK 类型闭包、虚拟编译器 host 和生成编排。旧 JS/MJS 文件仅转发,同属
|
||||
严格 checkJs 范围。新模块维护地图、依赖方向和修改命令见该目录 README。
|
||||
- 原 Chapter 文本回退产生 TS2309(default 与 export assignment 混用);
|
||||
VAST 同时产生 TS2304/2552(删除 import 后丢失 Player/PlayerOptions)。
|
||||
测试固定原转换表达式复现,不靠跳过声明检查或 any 替换解决。
|
||||
- 所有 20 个生态库现在统一走语义转换;加 core/i18n 共 22 个加载声明。格式化
|
||||
后以主 TS 5.9.3、旧 TS 4.3.5 整组检查,同时验证命名空间冲突和未解析依赖。
|
||||
生成期间仅作 layout 格式修复;SDK 原方法与 type alias 形状保留,相关 lint
|
||||
豁免限定在自动生成的 SDK 命名空间块。其余 20 份声明内容与起点一致。
|
||||
- VAST 通过单独 type-only 入口收集 @glomex/vast-ima-player 1.21.2 和
|
||||
@alugha/ima 2.1.0。直接 bundle VAST 根声明会因 workspace 链接一并内联核心,
|
||||
因此只 bundle SDK 闭包,再用 AST 放入模块内部 namespace,避免重复核心。
|
||||
原 Window 可选属性、必需回调、SDK 方法/私有成员约束保留;不新增 SDK 全局
|
||||
值或运行时加载。自动生成邻接 LICENSE.txt 保存上游 notices。
|
||||
- 新增 `check:editor-types` 并加入 ci:check;所有选择、声明检查、格式化、
|
||||
notices 和 libUris 生成成功后才写结果。只读检查拒绝缺失/漂移,不写文件。
|
||||
libUris 用 AST 定位唯一数组声明,避免找不到旧正则时静默漏更新;按包构建
|
||||
保持不更新总列表的旧行为。多文件最终写盘本身不承诺事务性。
|
||||
- 无新增依赖或锁变更;复用已固定 dts-bundle-generator 9.5.1、TS、ESLint、glob。
|
||||
两个真实编译器模块的名义类型不同,仅在工具边界适配,测试实际执行旧编译器。
|
||||
|
||||
## 验证与修正过程
|
||||
|
||||
- 4 项编辑器 Node 测试通过:core/ASR 原消费者;Chapter/VAST 旧红新绿、模块
|
||||
导入与全局消费;6 个类型误用分别被拒绝;全部 24 个输出与重生成一致;
|
||||
未知/重复选包及缺失/重复/非数组 libUris 拒绝。
|
||||
- 完整 baseline 522 通过,0 失败/跳过,覆盖旧 MJS 路径上的包类型回归。
|
||||
CI 50 项回归通过;严格 docs-tools 检查、全仓 lint(0 error/1 既有生成
|
||||
声明 warning)、目标 lint 与严格工具链通过。
|
||||
- 三浏览器实际 Monaco 各 1 项,共 3 通过,0 跳过/flaky:实际 common.js 中
|
||||
22 份加载声明一起检查,正例无诊断、三个坏参数各报 TS2322,并运行实际
|
||||
emit 的 Chapter 代码,真实受控媒体 ready 后销毁、实例归零。没有执行 VAST
|
||||
广告 SDK。完整 browser report 和版本/结果摘要见验证 JSON。
|
||||
- 首次浏览器检查失败在 23 vs 22 文件数:目录遗留 artplayer-plugin-websr.d.ts
|
||||
未列入实际 libUris。测试改为按实际加载列表取文件,原资产保留,未通过删除
|
||||
声明消除失败。失败报告已归档。旧资产的整体处置仍属 SITE-07。
|
||||
- 新虚拟 host 的模块正例最初失败,原因是 Windows 根路径尾部分隔符使目录
|
||||
比较不匹配;用 path.resolve 统一后相对导入和全部负例通过。SDK 声明初次
|
||||
layout lint 指出上游签名风格,采用限定范围保留原类型形状,未作语义格式替换。
|
||||
- 一次直接 node 调严格工具链检查被 Yarn 身份检查拒绝;按规定使用 pinned
|
||||
Yarn 重新执行成功,未绕过该门槛。原失败日志保留。
|
||||
|
||||
## 兼容与后续
|
||||
|
||||
本次兼容修正针对编辑器生成声明,生产根类型和 /runtime 类型均保持原内容。
|
||||
Chapter/VAST 编辑器从无效声明变成可严格消费声明,原合法回调和配置不需改写。
|
||||
VAST 初始化默认行为、Auto Thumbnail 首帧、真实设备/SDK、完整文档交互与三轮
|
||||
发布复盘仍开放。SITE-03/04/05 与 EX-03 接续文档产品流程和完整验收。
|
||||
|
||||
未重新执行全仓生产运行时套件或全局发布矩阵;本次变化没有生产源码/锁变更。
|
||||
没有手动 Chrome/iab 会话、远端 CI、推送或发布。构建/验证只证明上述工具与
|
||||
消费者范围。任务单独提交后审计;回退该提交会恢复旧生成链及 Chapter/VAST
|
||||
声明错误,需重新 build:ts,优先对具体回归单独修复。
|
||||
@@ -10,7 +10,8 @@
|
||||
| `yarn lint:fix` | 显式自动修复相同范围 |
|
||||
| `yarn typecheck` | 根/迁移包严格检查、当前与兼容 TS 消费;历史 NodeNext ESM 错误单独核对,见 typechecking.md |
|
||||
| `yarn typecheck:react` / `yarn typecheck:vue` | 原 React TSX / Vue SFC 示例严格检查,ci:check 同时执行对应 lint |
|
||||
| `yarn typecheck:docs-tools` / `yarn check:docs-smoke` | 严格检查 TS 示例生成器及 JS 命令门面;只读核对确定性生成的 readiness smoke,ci:check 执行 |
|
||||
| `yarn typecheck:docs-tools` / `yarn check:docs-smoke` | 严格检查 TS 示例/声明生成器及 JS/MJS 门面;只读核对确定性生成的 readiness smoke,ci:check 执行 |
|
||||
| `yarn check:editor-types` | 只读核对全部编辑器声明、SDK notices 和实际 libUris;主 TS 5.9.3/历史 4.3.5 整组语义检查,ci:check 执行 |
|
||||
| `yarn test:react-consumer` / `yarn test:vue-consumer` | 仓库外 tarball 安装、原框架示例、开发/生产三引擎;browser-smoke 执行并上传独立目录,本地证据不代替远端矩阵 |
|
||||
| `yarn test:unit` | 原播放/DASH 回归、同夹具的新旧公共契约与 JS/TS loader 验证 |
|
||||
| `yarn test:node` | test:unit 加工具链/文档构建回归,保留原 test:playback/test:dash-control 入口 |
|
||||
|
||||
+3
-2
@@ -4,7 +4,7 @@
|
||||
|
||||
基线:`40fcda6a37d0049d42e49c1e64e70d4fd9ba5f7f`。总任务 240 项,范围 22 个包及工作区/示例。
|
||||
|
||||
状态:todo 60 / doing 15 / blocked 0 / done 165 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
状态:todo 59 / doing 15 / blocked 0 / done 166 / deferred 0。风险 L/M/H 表示兼容风险,不表示工期。
|
||||
|
||||
前置依赖是启动条件;验收是完成条件。任务可以继续拆分,但不能复用或悄悄删除旧 ID。
|
||||
|
||||
@@ -382,7 +382,7 @@
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| SITE-01 | artplayer-vitepress, workspace<br>清点文档/示例/生成链 | BASE-04, BASE-05 | 中英文文档、插件页面、demo URL、编辑器声明与生成目录清单;六类 HTML 入口、prod/libs/code/example 加载行为及移动重定向 | 所有公开 API/插件有对应页面或明确补充任务;核实 BASE-DEMO-01 的历史 thumbnail 插件来源及 29 示例/36 HTML 路径;明确 BASE-05 所记录站点实际分发与未设 private 的 manifest 意图;接续 VENDOR-05/06/07/08 和 BASE-SITE-01/BASE-MEDIA-01,核对字体、Monaco、vConsole、console bundle 与样本来源及分发范围 | M | done |
|
||||
| SITE-SMOKE-01 | artplayer-vitepress, workspace<br>迁移示例生成器并验证真实就绪与清理 | SITE-01 | TS Markdown 解析/生成与浏览器运行模块;旧命令和 URL、稳定实例就绪 smoke、错误与资源清理 | 复现旧 malformed 死循环并保证有限失败;保留全部既有示例内容、生成确定且 check 只读;不再以 100ms 作为成功,验证原生就绪、异常、取消与清理;三浏览器检查,明确延迟交互与全部 233 示例仍需 EX-03 | M | done |
|
||||
| SITE-02 | artplayer-vitepress<br>整理声明与示例生成器 | SITE-01, ENG-04, ENG-06, SITE-SMOKE-01 | build-ts/build-test 生成链的可验证 TS 脚本 | 不靠字符串拼接掩盖声明错误,生成示例有真实断言或仅标 smoke;替换固定 100ms 成功判定,明确异步错误、清理和生成覆盖限制;坏代码块解析必须终止,覆盖 malformed 分支不推进 regexp 的回归 | M | todo |
|
||||
| SITE-02 | artplayer-vitepress<br>整理声明与示例生成器 | SITE-01, ENG-04, ENG-06, SITE-SMOKE-01 | build-ts/build-test 生成链的可验证 TS 脚本 | 不靠字符串拼接掩盖声明错误,生成示例有真实断言或仅标 smoke;替换固定 100ms 成功判定,明确异步错误、清理和生成覆盖限制;坏代码块解析必须终止,覆盖 malformed 分支不推进 regexp 的回归 | M | done |
|
||||
| SITE-03 | artplayer-vitepress<br>整理 i18n/文档/LLM 生成流程 | SITE-02 | build-i18n/build-docs/build-llm/trans-docs 的任务边界和错误处理 | 原命令兼容、生成可复现,翻译步骤不隐式运行远程服务;覆盖移动 loader 失败恢复 define、脚本依赖顺序、localhost/127.0.0.1 Run Code 目标和语言重定向 | M | todo |
|
||||
| SITE-04 | artplayer-vitepress<br>交叉核对逐包持续维护的文档 | CORE-21, SITE-03, PKG-CHAPTER-04, PKG-AMBILIGHT-04, PKG-AUDIO-04, PKG-AUTO-THUMB-04, PKG-VTT-THUMB-04, PKG-HLS-04, PKG-DASH-04, PKG-MULTI-SUB-04, PKG-JASSUB-04, PKG-MASK-04, PKG-ASR-04, PKG-ADS-04, PKG-VAST-04, PKG-CAST-04, PKG-DPIP-04, PKG-CANVAS-04, PKG-IFRAME-04, PKG-TOOL-THUMB-04, PKG-DANMUKU-06, PKG-MB-08 | 已随实现更新的中文/英文 API、包内实现地图、旧 JS 示例及已知能力限制的全包核对 | 未把缺环境的能力写成已验证,静态核对不等待设备任务;最终 demo 仍由 EX-03 验收;按 SITE-01 声明成员/候选标题清单逐项语义核对,补齐缺失的双语插件说明和 Danmuku 英文入口 | M | todo |
|
||||
| SITE-05 | artplayer-vitepress<br>构建文档站和验证链接/示例 | SITE-04, EX-01, EX-02, SITE-07 | VitePress 构建、链接与嵌入 demo 检查 | 文档构建、链接、嵌入路径与声明注入通过;真实完整 demo 保留 EX-03 独立门槛;核对 ENG-PM-01 登记的搜索 peer 范围和真实搜索行为 | M | todo |
|
||||
@@ -608,6 +608,7 @@
|
||||
- PKG-TOOL-THUMB-04: [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-runtime-types.md) [记录](baselines/thumbnail-runtime-types-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-public-types.md) [记录](baselines/thumbnail-public-types-validation.json) [记录](changes/2026-09-13-PKG-TOOL-THUMB-04-emitter.md) [记录](baselines/thumbnail-emitter-validation.json)
|
||||
- SITE-01: [记录](site-inventory.md) [记录](baselines/site-inventory.json) [记录](baselines/site-provenance.json) [记录](baselines/demo-additions.json) [记录](changes/2026-09-14-SITE-01-site-inventory.md) [记录](baselines/site-inventory-validation.json)
|
||||
- SITE-SMOKE-01: [记录](changes/2026-09-14-SITE-SMOKE-01-documentation-smoke.md) [记录](baselines/docs-smoke-validation.json) [记录](scripts/docs-smoke.test.mjs)
|
||||
- SITE-02: [记录](changes/2026-09-14-SITE-02-editor-declarations.md) [记录](baselines/editor-declarations-validation.json) [记录](changes/2026-09-14-SITE-SMOKE-01-documentation-smoke.md)
|
||||
- SITE-07: [记录](site-inventory.md) [记录](baselines/site-provenance.json)
|
||||
- EX-01: [记录](changes/2026-09-14-EX-01-react-consumer.md) [记录](baselines/react-consumer-validation.json) [记录](scripts/react-consumer.mjs)
|
||||
- EX-02: [记录](changes/2026-09-14-EX-02-vue-consumer.md) [记录](baselines/vue-consumer-validation.json) [记录](scripts/vue-consumer.mjs)
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# 进度与证据
|
||||
|
||||
## SITE-02 编辑器声明生成链完成
|
||||
|
||||
build:ts 与 core/plugin 转换器完成 TS 模块拆分,原 JS/MJS 命令/导入路径保留。
|
||||
修复 Chapter/VAST 文本回退产生的冲突导出与 SDK 类型丢失;22 份实际加载声明
|
||||
在内存格式化后用主 TS 5.9.3/旧 TS 4.3.5 整组检查,通过才写文件。其余 20 份
|
||||
声明与起点一致,生产源码/公开类型/锁不变。VAST SDK 类型保留私有命名空间与
|
||||
原签名,生成上游 notices;新增只读 check:editor-types 接入 CI。4 项编辑器
|
||||
测试、522 项 baseline、50 项 CI 回归、严格工具链/工具类型/lint 通过(根 lint
|
||||
1 条既有 warning)。三浏览器实际 Monaco 检查 22 份声明、拒绝坏参数并执行
|
||||
Chapter emit 的 ready/destroy,3 项通过。VAST 仅验类型,未执行广告。
|
||||
见[变更](changes/2026-09-14-SITE-02-editor-declarations.md)和
|
||||
[验证](baselines/editor-declarations-validation.json)。当前 240 项:166 done、
|
||||
15 doing、59 todo。下一步 SITE-03 站点/移动加载与编辑器流程;VAST 默认行为、
|
||||
Auto Thumbnail 首帧及插件最终验收保持开放。独立本地提交,无推送或发布。
|
||||
|
||||
## SITE-SMOKE-01 示例生成器与就绪检查完成
|
||||
|
||||
从 SITE-02 拆出文档示例工具,TS parser/generator/runtime 与严格检查的原 JS
|
||||
|
||||
@@ -78,7 +78,7 @@ export function captureSiteInventory() {
|
||||
pages: demo.pages,
|
||||
baselinePaths: { examplesAdded: demo.examples.filter(row => !historical.examples.some(old => old.source === row.source)).map(row => row.source), examplesRemoved: historical.examples.filter(row => !demo.examples.some(now => now.source === row.source)).map(row => row.source), htmlAdded: demo.pages.filter(row => !historical.pages.some(old => old.source === row.source)).map(row => row.source), htmlRemoved: historical.pages.filter(row => !demo.pages.some(now => now.source === row.source)).map(row => row.source) },
|
||||
editorDeclarations: [...read('docs/assets/js/common.js').matchAll(/'\.\/assets\/ts\/([^']+\.d\.ts)'/g)].map(match => ({ file: `docs/assets/ts/${match[1]}`, exists: fs.existsSync(path.join(root, 'docs/assets/ts', match[1])), owner: 'SITE-02' })),
|
||||
scripts: [...scriptFiles, ...files('scripts/docs-smoke').filter(file => file.endsWith('.ts'))].map(file => ({ file, sha256Lf: hash(read(file)) })),
|
||||
scripts: [...scriptFiles, ...files('scripts/docs-smoke').filter(file => file.endsWith('.ts')), ...files('scripts/editor-declarations').filter(file => file.endsWith('.ts'))].map(file => ({ file, sha256Lf: hash(read(file)) })),
|
||||
generationCommands: Object.fromEntries(Object.entries(json('package.json').scripts).filter(([name]) => /^(?:build:(?:types|ts|test|i18n|docs|llm|all)|ci:build)$/.test(name))),
|
||||
siteManifest: json('packages/artplayer-vitepress/package.json'),
|
||||
assets,
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
SITE-SMOKE-01 后续已将 build:test 拆为 TS 解析、生成和浏览器运行模块,新增
|
||||
确定性 examples.json 和 readonly check,替换 100ms done 为实例 ready/错误/清理。
|
||||
以下 SITE-01 的旧生成器问题属于历史发现;当前维护入口见
|
||||
[docs-smoke README](../scripts/docs-smoke/README.md)。声明生成仍归 SITE-02。
|
||||
[docs-smoke README](../scripts/docs-smoke/README.md)。SITE-02 后续已将声明生成
|
||||
迁到 `scripts/editor-declarations/`:全部 22 份加载声明整组验证,Chapter/VAST
|
||||
不再走删除 import 的文本回退。见[模块说明](../scripts/editor-declarations/README.md)。
|
||||
以下 SITE-01 对这些旧生成问题的描述是历史发现,站点/编辑器交互仍需后续验收。
|
||||
|
||||
SITE-01 在 `d62ab13a35c756ea567c426d4fbe00d893dd7e2b` 后核对当前源码。
|
||||
可重跑清单见 [site-inventory.json](baselines/site-inventory.json);它登记
|
||||
|
||||
+6
-2
@@ -4138,11 +4138,15 @@
|
||||
"ENG-06",
|
||||
"SITE-SMOKE-01"
|
||||
],
|
||||
"status": "todo",
|
||||
"status": "done",
|
||||
"risk": "M",
|
||||
"deliverable": "build-ts/build-test 生成链的可验证 TS 脚本",
|
||||
"acceptance": "不靠字符串拼接掩盖声明错误,生成示例有真实断言或仅标 smoke;替换固定 100ms 成功判定,明确异步错误、清理和生成覆盖限制;坏代码块解析必须终止,覆盖 malformed 分支不推进 regexp 的回归",
|
||||
"evidence": []
|
||||
"evidence": [
|
||||
"changes/2026-09-14-SITE-02-editor-declarations.md",
|
||||
"baselines/editor-declarations-validation.json",
|
||||
"changes/2026-09-14-SITE-SMOKE-01-documentation-smoke.md"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "SITE-03",
|
||||
|
||||
+2
-95
@@ -1,97 +1,4 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import process from 'node:process'
|
||||
import { ESLint } from 'eslint'
|
||||
import { glob } from 'glob'
|
||||
import compat from 'typescript-compat'
|
||||
import { generateCoreEditorDeclaration } from './editor-types.mjs'
|
||||
import { checkPluginEditorDeclaration, generatePluginEditorDeclaration } from './plugin-editor-types.mjs'
|
||||
import { runEditorDeclarations } from './editor-declarations/generate.ts'
|
||||
|
||||
function ensureDirExists(filePath) {
|
||||
const dir = path.dirname(filePath)
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
function parsePluginInfo(pluginPath) {
|
||||
// Use path.basename to handle both Unix and Windows paths correctly
|
||||
const file = path.basename(pluginPath)
|
||||
const baseName = file.replace('.d.ts', '')
|
||||
|
||||
const classNames = { 'artplayer-tool-iframe': 'ArtplayerToolIframe', 'artplayer-tool-thumbnail': 'ArtplayerToolThumbnail' }
|
||||
const name = classNames[baseName]
|
||||
? classNames[baseName]
|
||||
: baseName
|
||||
.split('-')
|
||||
.map((word, index) =>
|
||||
index === 0 ? word : word[0].toUpperCase() + word.slice(1),
|
||||
)
|
||||
.join('')
|
||||
|
||||
return { name, file }
|
||||
}
|
||||
|
||||
const reg = /^import.*$/gim
|
||||
const artplayerTSoutput = path.join('docs/assets/ts/artplayer.d.ts')
|
||||
const code = generateCoreEditorDeclaration()
|
||||
ensureDirExists(artplayerTSoutput)
|
||||
fs.writeFileSync(artplayerTSoutput, code.trim())
|
||||
console.log(`✨ Built ${artplayerTSoutput}`);
|
||||
|
||||
(async function () {
|
||||
const packageOf = file => path.basename(path.dirname(path.dirname(file)))
|
||||
const available = glob.sync('packages/artplayer-*-*/types/*.d.ts').filter(file => path.basename(file) === `${packageOf(file)}.d.ts`)
|
||||
const selected = process.argv.slice(2)
|
||||
for (const name of selected)
|
||||
assert(available.some(file => packageOf(file) === name), `Unknown declaration package: ${name}`)
|
||||
const pluginsTS = selected.length ? available.filter(file => selected.includes(packageOf(file))) : available
|
||||
const pluginFiles = []
|
||||
|
||||
for (let index = 0; index < pluginsTS.length; index++) {
|
||||
const type = pluginsTS[index]
|
||||
const { name, file } = parsePluginInfo(type)
|
||||
const source = String(fs.readFileSync(type))
|
||||
const semanticPlugin = ['artplayerPluginAutoThumbnail', 'artplayerPluginJassub', 'artplayerPluginDanmukuMask', 'artplayerPluginDanmuku', 'artplayerPluginChromecast', 'artplayerPluginAsr', 'artplayerPluginMultipleSubtitles', 'artplayerPluginVttThumbnail', 'artplayerPluginHlsControl', 'artplayerPluginAudioTrack', 'artplayerPluginDashControl', 'artplayerPluginAds', 'artplayerPluginAmbilight', 'artplayerProxyCanvas', 'artplayerProxyMediabunny', 'artplayerPluginDocumentPip', 'ArtplayerToolIframe', 'ArtplayerToolThumbnail'].includes(name)
|
||||
const localTypes = name === 'artplayerProxyMediabunny' ? { './media': fs.readFileSync(path.join(path.dirname(type), 'media.d.ts'), 'utf8') } : {}
|
||||
const code = semanticPlugin
|
||||
? generatePluginEditorDeclaration(source, name, localTypes)
|
||||
: `${source.replace(reg, '')}\nexport = ${name};\nexport as namespace ${name};\n`
|
||||
if (semanticPlugin) {
|
||||
const core = fs.readFileSync(artplayerTSoutput, 'utf8')
|
||||
const diagnostics = [...checkPluginEditorDeclaration(code, core), ...checkPluginEditorDeclaration(code, core, '', compat)]
|
||||
if (diagnostics.length)
|
||||
throw new Error(`Invalid ${name} editor declaration: ${JSON.stringify(diagnostics)}`)
|
||||
}
|
||||
const output = path.join('docs/assets/ts', file)
|
||||
ensureDirExists(output)
|
||||
fs.writeFileSync(output, code.trim())
|
||||
console.log(`✨ Built ${output}`)
|
||||
pluginFiles.push(file)
|
||||
}
|
||||
|
||||
pluginFiles.sort()
|
||||
const languageFile = 'artplayer-i18n.d.ts'
|
||||
fs.writeFileSync(path.join('docs/assets/ts', languageFile), `declare module 'artplayer/i18n/*' {\n const language: NonNullable<Artplayer.I18n['en']>\n export default language\n}\n`)
|
||||
const allFiles = [...pluginFiles, 'artplayer.d.ts', languageFile]
|
||||
const eslint = new ESLint({ fix: true, fixTypes: ['layout'] })
|
||||
const results = await eslint.lintFiles(allFiles.map(file => path.join('docs/assets/ts', file)))
|
||||
await ESLint.outputFixes(results)
|
||||
if (results.some(result => result.errorCount)) {
|
||||
const formatter = await eslint.loadFormatter('stylish')
|
||||
throw new Error(formatter.format(results))
|
||||
}
|
||||
if (selected.length)
|
||||
return
|
||||
const commonJsPath = path.join('docs/assets/js/common.js')
|
||||
const commonJsContent = fs.readFileSync(commonJsPath, 'utf-8')
|
||||
const newLibUris = allFiles.map(file => `'./assets/ts/${file}'`).join(',\n ')
|
||||
const newContent = commonJsContent.replace(
|
||||
/let libUris = \[([\s\S]*?)\]/,
|
||||
`let libUris = [\n ${newLibUris},\n ]`,
|
||||
)
|
||||
ensureDirExists(commonJsPath)
|
||||
fs.writeFileSync(commonJsPath, newContent)
|
||||
console.log(`✨ Updated libUris in ${commonJsPath}`)
|
||||
})()
|
||||
await runEditorDeclarations(process.argv.slice(2))
|
||||
@@ -0,0 +1,70 @@
|
||||
# Editor declarations
|
||||
|
||||
Run `yarn build:ts` from the repository root using Node 24.21.0 and Yarn 1.22.22.
|
||||
Existing declaration URLs and package selection arguments remain supported.
|
||||
`yarn build:ts artplayer-plugin-chapter` selects that package plus shared core
|
||||
and language declarations. `yarn check:editor-types` checks the complete output
|
||||
without writing. Unknown/duplicate selections fail before generating or writing.
|
||||
|
||||
| Module | Responsibility |
|
||||
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `../build-ts.js` | Existing CLI path, checked JavaScript shim |
|
||||
| `generate.ts` | Discovery, names, formatting, whole-set validation, writes/checks and editor libUris |
|
||||
| `core.ts` | Core public source bundling, constructor and named/generic aliases |
|
||||
| `plugin.ts` | AST conversion of default exports, callable CommonJS namespaces, type aliases and Window augmentations |
|
||||
| `syntax.ts` | Public compiler syntax diagnostics and supported dependency definition kinds |
|
||||
| `dependencies.ts`, `vast-sdk.ts` | Type-only VAST SDK dependency closure; no advertising scripts |
|
||||
| `validation.ts` | Standalone virtual compiler host, relative imports and rejection of hidden external dependencies |
|
||||
| `../editor-types.mjs`, `../plugin-editor-types.mjs` | Existing tooling import paths forwarding to TypeScript |
|
||||
|
||||
`yarn typecheck:docs-tools` checks these modules and the original JS/MJS shims.
|
||||
Orchestration depends on conversion and validation; conversion does not write.
|
||||
Public package declarations remain the source of truth. Do not hand-edit
|
||||
`docs/assets/ts/*.d.ts`.
|
||||
|
||||
All selected declarations are formatted in memory using layout-only ESLint fixes,
|
||||
then checked together with TypeScript 5.9.3 and 4.3.5, without `skipLibCheck` or
|
||||
ambient dependency discovery. This checks cross-package globals too. SDK methods
|
||||
and type aliases retain upstream shapes; the generated SDK block has a narrowly
|
||||
scoped lint exception for those two style rules. The two compiler packages have
|
||||
nominally distinct AST types: the historical module is adapted at the boundary
|
||||
and exercised as the real older compiler. Node native type stripping runs tools.
|
||||
|
||||
Legacy MJS helpers retain synchronous functions and diagnostic shapes; existing
|
||||
package consumer tests still use them. Core retains its existing bundler and
|
||||
private definitions namespace. Plugins preserve callable/default aliases and
|
||||
exported type namespaces. Unsupported imports/re-exports and invalid syntax fail.
|
||||
|
||||
VAST's `Player` and `PlayerOptions` come from the installed, lockfile-pinned
|
||||
`@glomex/vast-ima-player` 1.21.2 and `@alugha/ima` 2.1.0 declarations. A dedicated
|
||||
type-only SDK entry avoids bundling a second copy of the linked workspace core.
|
||||
SDK types stay in the plugin's module-private definitions namespace, not global
|
||||
runtime values. The optional Window hook and required callback remain unchanged.
|
||||
Adjacent generated `artplayer-plugin-vast.LICENSE.txt` preserves upstream notices.
|
||||
This does not settle VAST's runtime default-behavior compatibility decision.
|
||||
|
||||
The editor loads 22 declarations: core, 20 ecosystem libraries and i18n. The
|
||||
unreferenced legacy `artplayer-plugin-websr.d.ts` asset is not in the `common.js`
|
||||
library list and is not owned or deleted here. Monaco tests follow the actual
|
||||
list. AST updates require exactly one array-valued `libUris` declaration; missing
|
||||
or ambiguous declarations fail. Package-only builds leave that list alone.
|
||||
|
||||
Generation validates all selected results before any writes, but does not provide
|
||||
a multi-file filesystem transaction. `--check` normalizes CRLF for comparison,
|
||||
writes nothing and rejects missing/stale output. No timestamps are generated.
|
||||
Rebuild then check after changes to public types, SDK versions or formatting.
|
||||
|
||||
```sh
|
||||
yarn typecheck:docs-tools
|
||||
yarn build:ts
|
||||
yarn check:editor-types
|
||||
node --test test/editor-types.test.js
|
||||
yarn test:baseline
|
||||
yarn test:browser test/browser/editor-declarations.spec.js --workers=1
|
||||
```
|
||||
|
||||
Browser coverage uses the actual repository Monaco assets, all loaded declarations,
|
||||
positive/negative consumers and emitted Chapter code against controlled media.
|
||||
VAST is type-checked only: no ad request or SDK/network/device acceptance. Full
|
||||
editor UI, routes, example coverage and release reviews remain SITE-03/04/05,
|
||||
EX-03 and release tasks. SITE-02 installs no new dependencies.
|
||||
@@ -0,0 +1,145 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { createRequire } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { generateDtsBundle } from 'dts-bundle-generator'
|
||||
import ts from 'typescript'
|
||||
import compat from 'typescript-compat'
|
||||
|
||||
const root = fileURLToPath(new URL('../../', import.meta.url))
|
||||
const factory = ts.factory
|
||||
|
||||
/** Put flattened definitions in a private scope so public aliases cannot refer to themselves. */
|
||||
export function asGlobalDeclaration(code: string, globalName: string) {
|
||||
assert(/^[A-Z_$][\w$]*$/i.test(globalName), 'Invalid editor global name')
|
||||
const source = ts.createSourceFile('bundle.d.ts', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
const exports = new Map<string, string>()
|
||||
const declarations = new Map<string, ts.InterfaceDeclaration | ts.TypeAliasDeclaration | ts.ClassDeclaration>()
|
||||
const definitions: ts.Statement[] = []
|
||||
for (const node of source.statements) {
|
||||
if (ts.isExportDeclaration(node)) {
|
||||
assert(!node.moduleSpecifier && node.exportClause && ts.isNamedExports(node.exportClause), 'Editor bundle must contain no unresolved exports')
|
||||
for (const item of node.exportClause.elements)
|
||||
exports.set(item.name.text, (item.propertyName || item.name).text)
|
||||
continue
|
||||
}
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isClassDeclaration(node), `Unsupported editor declaration: ${ts.SyntaxKind[node.kind]}`)
|
||||
assert(node.name, 'Editor definitions must be named')
|
||||
const name = node.name.text
|
||||
assert(!declarations.has(name), `Duplicate bundled declaration: ${name}`)
|
||||
declarations.set(name, node)
|
||||
if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword))
|
||||
exports.set(name, name)
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
}
|
||||
const defaultName = exports.get('default')
|
||||
const defaultDeclaration = defaultName && declarations.get(defaultName)
|
||||
assert(defaultName && defaultDeclaration && ts.isClassDeclaration(defaultDeclaration), 'Core editor requires the actual default constructor class')
|
||||
const definitionName = `${globalName}Definitions`
|
||||
assert(!declarations.has(definitionName), 'Editor definition namespace collides with source')
|
||||
const qualified = (name: string) => factory.createQualifiedName(factory.createIdentifier(definitionName), factory.createIdentifier(name))
|
||||
const aliases: ts.TypeAliasDeclaration[] = []
|
||||
for (const [name, local] of exports) {
|
||||
if (name === 'default')
|
||||
continue
|
||||
const declaration = declarations.get(local)
|
||||
assert(declaration, `Missing bundled export: ${local}`)
|
||||
const parameters = declaration.typeParameters
|
||||
aliases.push(factory.createTypeAliasDeclaration(
|
||||
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
||||
name,
|
||||
parameters,
|
||||
factory.createTypeReferenceNode(qualified(local), parameters?.map(parameter => factory.createTypeReferenceNode(parameter.name))),
|
||||
))
|
||||
}
|
||||
const namespace = (name: string, nodes: ts.Statement[]) => factory.createModuleDeclaration(
|
||||
[factory.createModifier(ts.SyntaxKind.DeclareKeyword)],
|
||||
factory.createIdentifier(name),
|
||||
factory.createModuleBlock(nodes),
|
||||
ts.NodeFlags.Namespace,
|
||||
)
|
||||
const statements = [
|
||||
namespace(definitionName, definitions),
|
||||
factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createVariableDeclarationList([
|
||||
factory.createVariableDeclaration(globalName, undefined, factory.createTypeQueryNode(qualified(defaultName))),
|
||||
], ts.NodeFlags.Const)),
|
||||
factory.createTypeAliasDeclaration(undefined, globalName, undefined, factory.createTypeReferenceNode(qualified(defaultName))),
|
||||
namespace(globalName, aliases),
|
||||
factory.createExportAssignment(undefined, true, factory.createIdentifier(globalName)),
|
||||
factory.createNamespaceExportDeclaration(factory.createIdentifier(globalName)),
|
||||
]
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||
return `// Generated from packages/artplayer/public/artplayer.ts by yarn build:ts. Do not edit.\n/* eslint-disable ts/no-redeclare, ts/no-namespace -- UMD constructor and named types share the global export. */\n${printer.printFile(factory.updateSourceFile(source, statements))}`
|
||||
}
|
||||
|
||||
export function generateCoreEditorDeclaration() {
|
||||
const require = createRequire(import.meta.url)
|
||||
const bundlerRequire = createRequire(require.resolve('dts-bundle-generator'))
|
||||
assert.equal(bundlerRequire('typescript'), ts, 'Editor bundler must use the pinned workspace compiler')
|
||||
const [code] = generateDtsBundle([{
|
||||
filePath: path.join(root, 'packages/artplayer/public/artplayer.ts'),
|
||||
output: { exportReferencedTypes: false, noBanner: true },
|
||||
}], { preferredConfigPath: path.join(root, 'scripts/tsconfig.editor.json') })
|
||||
assert(code, 'Core bundle is empty')
|
||||
const declaration = asGlobalDeclaration(code, 'Artplayer')
|
||||
for (const compiler of [ts, compat])
|
||||
assert.deepEqual(checkCoreEditorDeclaration(declaration, compiler as unknown as typeof ts), [], `Invalid editor declaration: TS ${compiler.version}`)
|
||||
return declaration
|
||||
}
|
||||
|
||||
export function checkCoreEditorDeclaration(code: string, compiler: typeof ts = ts) {
|
||||
const folder = path.join(root, 'refactor/.cache/editor-semantic')
|
||||
const declaration = path.join(folder, 'artplayer.d.ts')
|
||||
const sources = new Map([
|
||||
[declaration, code],
|
||||
[path.join(folder, 'global.ts'), `
|
||||
const option: Artplayer.OptionInput = { container: '#player' }
|
||||
const player: Artplayer = new Artplayer(option, function (art) {
|
||||
const same: Artplayer = this
|
||||
const other: Artplayer = art
|
||||
void [same, other]
|
||||
})
|
||||
const factory: Artplayer.PluginFactory<Artplayer, { name: string }> = function (art) {
|
||||
return { name: String(art.id + this.id) }
|
||||
}
|
||||
const plugins: Promise<Artplayer.Plugins> = player.plugins.add(factory)
|
||||
const emitter: Artplayer.Emitter<{ value: [number] }> = new Artplayer.Emitter()
|
||||
emitter.on('value', count => count.toFixed()).emit('value', 2)
|
||||
const language: NonNullable<Artplayer.I18n['en']> = { Play: 'Play' }
|
||||
const configuration: Artplayer.Config = Artplayer.config
|
||||
// @ts-expect-error Private flattened definitions must not leak into the editor global scope.
|
||||
const leaked: ArtplayerDefinitions.Config = Artplayer.config
|
||||
// @ts-expect-error Required container is not optional.
|
||||
new Artplayer({ url: '' })
|
||||
// @ts-expect-error Named aliases must not degrade to any through circular definitions.
|
||||
const invalidOption: Artplayer.Option = { container: 123, url: '' }
|
||||
// @ts-expect-error Plugin callback results retain the selected result type.
|
||||
const invalidFactory: Artplayer.PluginFactory<Artplayer, number> = () => 'bad'
|
||||
// @ts-expect-error Generic event payloads stay checked.
|
||||
emitter.emit('value', 'bad')
|
||||
void [plugins, language, configuration, invalidOption, invalidFactory, leaked]
|
||||
`],
|
||||
[path.join(folder, 'module.ts'), `
|
||||
import Player = require('./artplayer')
|
||||
const player: Player = new Player({ container: '#player' })
|
||||
const option: Player.OptionInput = { container: '#player' }
|
||||
// @ts-expect-error The UMD export is the constructor, not a default wrapper object.
|
||||
Player.default
|
||||
void [player, option]
|
||||
`],
|
||||
])
|
||||
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs }
|
||||
const host = compiler.createCompilerHost(options)
|
||||
const getSourceFile = host.getSourceFile.bind(host)
|
||||
const exists = host.fileExists.bind(host)
|
||||
const directoryExists = host.directoryExists?.bind(host)
|
||||
host.fileExists = file => sources.has(path.resolve(file)) || exists(file)
|
||||
host.directoryExists = directory => path.resolve(directory) === folder || !!directoryExists?.(directory)
|
||||
host.getSourceFile = (file, version, onError, create) => sources.has(path.resolve(file))
|
||||
? compiler.createSourceFile(file, sources.get(path.resolve(file))!, version, true)
|
||||
: getSourceFile(file, version, onError, create)
|
||||
const program = compiler.createProgram([...sources.keys()], options, host)
|
||||
for (const file of program.getSourceFiles())
|
||||
assert(sources.has(path.resolve(file.fileName)) || program.isSourceFileDefaultLibrary(file), `Editor types escaped the standalone bundle: ${file.fileName}`)
|
||||
return compiler.getPreEmitDiagnostics(program).map(diagnostic => ({ code: diagnostic.code, message: compiler.flattenDiagnosticMessageText(diagnostic.messageText, '\n') }))
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { generateDtsBundle } from 'dts-bundle-generator'
|
||||
import ts from 'typescript'
|
||||
import { parseDeclaration } from './syntax.ts'
|
||||
|
||||
export function vastSdkDeclarations(): ts.Statement[] {
|
||||
const root = fileURLToPath(new URL('../../', import.meta.url))
|
||||
const [code] = generateDtsBundle([{
|
||||
filePath: path.join(root, 'scripts/editor-declarations/vast-sdk.ts'),
|
||||
libraries: { inlinedLibraries: ['@glomex/vast-ima-player', '@alugha/ima'], allowedTypesLibraries: [] },
|
||||
output: { noBanner: true, exportReferencedTypes: false },
|
||||
}], { preferredConfigPath: path.join(root, 'scripts/tsconfig.editor.json') })
|
||||
assert(code, 'SDK bundle is empty')
|
||||
return [...parseDeclaration(code, 'vast-sdk.d.ts').statements].filter((node) => {
|
||||
if (!ts.isExportDeclaration(node))
|
||||
return true
|
||||
assert(!node.moduleSpecifier && node.exportClause && ts.isNamedExports(node.exportClause)
|
||||
&& node.exportClause.elements.length === 0, 'Unexpected SDK re-export')
|
||||
return false
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { ESLint } from 'eslint'
|
||||
import { globSync } from 'glob'
|
||||
import ts from 'typescript'
|
||||
import compat from 'typescript-compat'
|
||||
import { generateCoreEditorDeclaration } from './core.ts'
|
||||
import { vastSdkDeclarations } from './dependencies.ts'
|
||||
import { generatePluginEditorDeclaration } from './plugin.ts'
|
||||
import { checkStandaloneDeclarations } from './validation.ts'
|
||||
|
||||
export function pluginIdentity(file: string): { name: string, file: string, packageName: string } {
|
||||
const packageName = path.basename(path.dirname(path.dirname(file)))
|
||||
const names: Record<string, string> = { 'artplayer-tool-iframe': 'ArtplayerToolIframe', 'artplayer-tool-thumbnail': 'ArtplayerToolThumbnail' }
|
||||
const name = names[packageName] || packageName.split('-').map((word, index) => index ? word.charAt(0).toUpperCase() + word.slice(1) : word).join('')
|
||||
return { name, file: path.basename(file), packageName }
|
||||
}
|
||||
|
||||
export function editorLibUris(code: string, files: string[]): string {
|
||||
const source = ts.createSourceFile('common.js', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS)
|
||||
const lists: ts.ArrayLiteralExpression[] = []
|
||||
const visit = (node: ts.Node): void => {
|
||||
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === 'libUris') {
|
||||
assert(node.initializer && ts.isArrayLiteralExpression(node.initializer), 'libUris must be an array initializer')
|
||||
lists.push(node.initializer)
|
||||
}
|
||||
ts.forEachChild(node, visit)
|
||||
}
|
||||
visit(source)
|
||||
assert(lists.length === 1 && lists[0], 'Expected exactly one libUris declaration')
|
||||
const list = lists[0]
|
||||
const value = `[\n ${files.map(file => `'./assets/ts/${file}'`).join(',\n ')},\n ]`
|
||||
return code.slice(0, list.getStart(source)) + value + code.slice(list.end)
|
||||
}
|
||||
|
||||
export async function generateEditorDeclarations(selected: string[] = []): Promise<Map<string, string>> {
|
||||
const available = globSync('packages/artplayer-*-*/types/*.d.ts').filter(file => path.basename(file) === `${pluginIdentity(file).packageName}.d.ts`).sort()
|
||||
for (const name of selected)
|
||||
assert(available.some(file => pluginIdentity(file).packageName === name), `Unknown declaration package: ${name}`)
|
||||
assert(new Set(selected).size === selected.length, 'Duplicate declaration package selection')
|
||||
const sources = selected.length ? available.filter(file => selected.includes(pluginIdentity(file).packageName)) : available
|
||||
const core = generateCoreEditorDeclaration()
|
||||
const outputs = new Map<string, string>([['docs/assets/ts/artplayer.d.ts', core]])
|
||||
const pluginFiles: string[] = []
|
||||
for (const sourceFile of sources) {
|
||||
const { name, file, packageName } = pluginIdentity(sourceFile)
|
||||
const localTypes: Record<string, string> = packageName === 'artplayer-proxy-mediabunny' ? { './media': fs.readFileSync(path.join(path.dirname(sourceFile), 'media.d.ts'), 'utf8') } : {}
|
||||
const dependencies = packageName === 'artplayer-plugin-vast' ? vastSdkDeclarations() : []
|
||||
const code = generatePluginEditorDeclaration(fs.readFileSync(sourceFile, 'utf8'), name, localTypes, dependencies)
|
||||
outputs.set(path.join('docs/assets/ts', file), code)
|
||||
pluginFiles.push(file)
|
||||
}
|
||||
const languageFile = 'artplayer-i18n.d.ts'
|
||||
outputs.set(path.join('docs/assets/ts', languageFile), `declare module 'artplayer/i18n/*' {\n const language: NonNullable<Artplayer.I18n['en']>\n export default language\n}\n`)
|
||||
const eslint = new ESLint({ fix: true, fixTypes: ['layout'] })
|
||||
for (const [file, code] of outputs) {
|
||||
const [result] = await eslint.lintText(code, { filePath: file })
|
||||
assert(result && !result.errorCount, `Invalid formatted editor declaration ${file}: ${JSON.stringify(result?.messages)}`)
|
||||
outputs.set(file, result.output || code)
|
||||
}
|
||||
// Both actual compilers check the formatted files together, including global collisions.
|
||||
const declarations = new Map([...outputs].map(([file, code]) => [path.basename(file), code]))
|
||||
for (const compiler of [ts, compat as unknown as typeof ts])
|
||||
assert.deepEqual(checkStandaloneDeclarations(declarations, compiler), [], `Invalid editor declarations (TS ${compiler.version})`)
|
||||
if (!selected.length) {
|
||||
const file = 'docs/assets/js/common.js'
|
||||
outputs.set(file, editorLibUris(fs.readFileSync(file, 'utf8'), [...pluginFiles.sort(), 'artplayer.d.ts', languageFile]))
|
||||
}
|
||||
if (sources.some(file => pluginIdentity(file).packageName === 'artplayer-plugin-vast')) {
|
||||
const notices = [['@glomex/vast-ima-player', 'LICENSE'], ['@alugha/ima', 'LICENSE.md']].map(([name, file]) => `${name}\n${fs.readFileSync(path.join('node_modules', name!, file!), 'utf8').replaceAll('\r\n', '\n').trim()}\n`).join('\n')
|
||||
outputs.set('docs/assets/ts/artplayer-plugin-vast.LICENSE.txt', notices)
|
||||
}
|
||||
return outputs
|
||||
}
|
||||
|
||||
export async function runEditorDeclarations(args: string[]): Promise<void> {
|
||||
assert(args.every(arg => arg === '--check' || !arg.startsWith('-')), 'Use yarn build:ts [--check] [package ...]')
|
||||
const outputs = await generateEditorDeclarations(args.filter(arg => arg !== '--check'))
|
||||
for (const [file, code] of outputs) {
|
||||
if (args.includes('--check')) {
|
||||
assert.equal(fs.readFileSync(file, 'utf8').replaceAll('\r\n', '\n'), code.replaceAll('\r\n', '\n'), `Editor declaration drift: ${file}`)
|
||||
}
|
||||
else {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true })
|
||||
fs.writeFileSync(file, code)
|
||||
}
|
||||
}
|
||||
console.log(`Editor declarations ${args.includes('--check') ? 'checked' : 'generated'}: ${outputs.size} outputs; all selected declarations checked with current and compatibility compilers`)
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import ts from 'typescript'
|
||||
import { exportedDefinition, parseDeclaration } from './syntax.ts'
|
||||
|
||||
// Migrate each package explicitly; unknown imports/exports must not disappear silently.
|
||||
export function generatePluginEditorDeclaration(code: string, name: string, localTypes: Record<string, string> = {}, dependencies: ts.Statement[] = []) {
|
||||
assert(/^[a-z_$][\w$]*$/i.test(name), 'Invalid plugin global')
|
||||
let source = parseDeclaration(code)
|
||||
const expanded: ts.Statement[] = []
|
||||
for (const node of source.statements) {
|
||||
if (!ts.isExportDeclaration(node) || !node.moduleSpecifier) {
|
||||
expanded.push(node)
|
||||
continue
|
||||
}
|
||||
assert(node.isTypeOnly, 'Unsupported plugin editor declaration: runtime re-export')
|
||||
assert(ts.isStringLiteral(node.moduleSpecifier), 'Expected a literal type module')
|
||||
const dependency = localTypes[node.moduleSpecifier.text]
|
||||
assert(typeof dependency === 'string' && node.exportClause && ts.isNamedExports(node.exportClause), 'Unsupported editor type re-export')
|
||||
const names = node.exportClause.elements.map((item) => {
|
||||
assert(!item.propertyName, 'Renamed editor type re-export is unsupported')
|
||||
return item.name.text
|
||||
})
|
||||
const types = parseDeclaration(dependency, 'dependency.d.ts')
|
||||
const definitions = types.statements.filter(item => !ts.isImportDeclaration(item))
|
||||
assert(definitions.every(item => ts.isInterfaceDeclaration(item) || ts.isTypeAliasDeclaration(item)), 'Editor dependencies must contain only types')
|
||||
assert.deepEqual(definitions.map(item => item.name.text).sort(), names.sort(), 'Editor re-export must explicitly cover its local type definitions')
|
||||
expanded.push(...types.statements)
|
||||
}
|
||||
// Reparse combined statements so comments and text positions belong to one file.
|
||||
source = ts.createSourceFile('plugin.d.ts', expanded.map(node => ts.createPrinter().printNode(ts.EmitHint.Unspecified, node, node.getSourceFile())).join('\n'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
if (source.statements.some(node => ts.isExportAssignment(node) && node.isExportEquals))
|
||||
return generateCommonJSPluginEditor(source, name)
|
||||
const factory = ts.factory
|
||||
const definitions: ts.Statement[] = []
|
||||
const globals: ts.ModuleDeclaration[] = []
|
||||
const aliases: ts.TypeAliasDeclaration[] = []
|
||||
const internal = `${name}Definitions`
|
||||
let exported = false
|
||||
let callable = false
|
||||
let classExport = false
|
||||
for (const node of source.statements) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
assert(ts.isStringLiteral(node.moduleSpecifier), 'Expected a literal import')
|
||||
if (dependencies.length && node.moduleSpecifier.text === '@glomex/vast-ima-player') {
|
||||
const bindings = node.importClause?.namedBindings
|
||||
assert(node.importClause?.isTypeOnly && !node.importClause.name && bindings && ts.isNamedImports(bindings), 'Expected type-only SDK imports')
|
||||
assert.deepEqual(bindings.elements.map((item) => {
|
||||
assert(!item.propertyName)
|
||||
return item.name.text
|
||||
}).sort(), ['Player', 'PlayerOptions'])
|
||||
continue
|
||||
}
|
||||
assert(node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported plugin editor import')
|
||||
continue
|
||||
}
|
||||
if (ts.isModuleDeclaration(node)) {
|
||||
assert(node.flags & ts.NodeFlags.GlobalAugmentation, 'Only explicit global augmentations are supported')
|
||||
assert(node.body && ts.isModuleBlock(node.body) && node.body.statements.every(item => ts.isInterfaceDeclaration(item) && item.name.text === 'Window'), 'Only Window augmentations are supported')
|
||||
globals.push(node)
|
||||
continue
|
||||
}
|
||||
if (ts.isExportAssignment(node)) {
|
||||
assert(!node.isExportEquals && ts.isIdentifier(node.expression) && node.expression.text === name, 'Unexpected plugin default export')
|
||||
exported = true
|
||||
continue
|
||||
}
|
||||
if (ts.isVariableStatement(node)) {
|
||||
const values = node.declarationList.declarations
|
||||
const value = values[0]
|
||||
assert(values.length === 1 && value && ts.isIdentifier(value.name) && value.name.text === name && value.type && ts.isFunctionTypeNode(value.type), 'Unexpected plugin callable variable')
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
callable = true
|
||||
continue
|
||||
}
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node), 'Unsupported plugin editor declaration')
|
||||
assert(node.name && node.name.text !== internal, 'Invalid plugin declaration name')
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) {
|
||||
assert.equal(node.name.text, name, 'Unexpected plugin callable')
|
||||
callable = true
|
||||
classExport = ts.isClassDeclaration(node)
|
||||
continue
|
||||
}
|
||||
if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
aliases.push(factory.createTypeAliasDeclaration(
|
||||
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
||||
node.name,
|
||||
node.typeParameters,
|
||||
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(internal), node.name), node.typeParameters?.map(parameter => factory.createTypeReferenceNode(parameter.name))),
|
||||
))
|
||||
}
|
||||
}
|
||||
assert(exported && callable, 'Plugin editor requires a default function or class')
|
||||
const namespace = (identifier: string, statements: ts.Statement[]) => factory.createModuleDeclaration([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createIdentifier(identifier), factory.createModuleBlock(statements), ts.NodeFlags.Namespace)
|
||||
const statements = [
|
||||
...globals,
|
||||
namespace(internal, definitions),
|
||||
factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createVariableDeclarationList([
|
||||
factory.createVariableDeclaration(name, undefined, factory.createTypeQueryNode(factory.createQualifiedName(factory.createIdentifier(internal), factory.createIdentifier(name)))),
|
||||
], ts.NodeFlags.Const)),
|
||||
...(classExport ? [factory.createTypeAliasDeclaration(undefined, name, undefined, factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(internal), factory.createIdentifier(name))))] : []),
|
||||
namespace(name, aliases),
|
||||
factory.createExportAssignment(undefined, true, factory.createIdentifier(name)),
|
||||
factory.createNamespaceExportDeclaration(factory.createIdentifier(name)),
|
||||
]
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||
const dependencySource = dependencies[0]?.getSourceFile()
|
||||
assert(dependencies.every(node => node.getSourceFile() === dependencySource), 'SDK definitions must share one source file')
|
||||
const dependencyNamespace = dependencySource
|
||||
? `/* eslint-disable ts/method-signature-style, ts/consistent-type-definitions -- Preserve upstream SDK declaration shapes. */\n${printer.printNode(ts.EmitHint.Unspecified, namespace(internal, dependencies.map(exportedDefinition)), dependencySource)}\n/* eslint-enable ts/method-signature-style, ts/consistent-type-definitions */\n`
|
||||
: ''
|
||||
return `// Generated from the package public declaration by yarn build:ts. Do not edit.\n/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */\n${dependencyNamespace}${statements.map(node => printer.printNode(ts.EmitHint.Unspecified, node, source)).join('\n')}\n`
|
||||
}
|
||||
|
||||
function generateCommonJSPluginEditor(source: ts.SourceFile, name: string) {
|
||||
const statements: ts.Statement[] = []
|
||||
let namespace = false
|
||||
let callable = false
|
||||
let exported = false
|
||||
let global = false
|
||||
let classExport = false
|
||||
for (const node of source.statements) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
assert(ts.isStringLiteral(node.moduleSpecifier) && node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported CommonJS plugin editor import')
|
||||
continue
|
||||
}
|
||||
if (ts.isModuleDeclaration(node)) {
|
||||
assert.equal(node.name.text, name, 'Unexpected plugin namespace')
|
||||
assert(node.body && ts.isModuleBlock(node.body) && node.body.statements.every(item => ts.isInterfaceDeclaration(item) || ts.isTypeAliasDeclaration(item)), 'Editor namespace must contain only public type declarations')
|
||||
namespace = true
|
||||
}
|
||||
else if (ts.isClassDeclaration(node)) {
|
||||
assert.equal(node.name?.text, name, 'Unexpected CommonJS editor class')
|
||||
callable = true
|
||||
classExport = true
|
||||
}
|
||||
else if (ts.isVariableStatement(node)) {
|
||||
const definitions = node.declarationList.declarations
|
||||
assert.equal(definitions.length, 1)
|
||||
const definition = definitions[0]
|
||||
assert(definition && ts.isIdentifier(definition.name) && definition.type)
|
||||
assert.equal(definition.name.text, name)
|
||||
assert(ts.isTypeReferenceNode(definition.type) && ts.isQualifiedName(definition.type.typeName)
|
||||
&& ts.isIdentifier(definition.type.typeName.left) && definition.type.typeName.left.text === name && definition.type.typeName.right.text === 'Factory', 'Editor export must use its public Factory interface')
|
||||
callable = true
|
||||
}
|
||||
else if (ts.isExportAssignment(node)) {
|
||||
assert(node.isExportEquals && ts.isIdentifier(node.expression) && node.expression.text === name, 'Unexpected CommonJS plugin export')
|
||||
exported = true
|
||||
}
|
||||
else if (ts.isNamespaceExportDeclaration(node)) {
|
||||
assert.equal(node.name.text, name)
|
||||
global = true
|
||||
}
|
||||
else {
|
||||
assert.fail('Unsupported CommonJS plugin editor declaration')
|
||||
}
|
||||
statements.push(node)
|
||||
}
|
||||
assert(namespace && callable && exported && global, 'Incomplete CommonJS plugin editor declaration')
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||
const bridge = classExport ? '' : '/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */\n'
|
||||
return `// Generated from the package public declaration by yarn build:ts. Do not edit.\n${bridge}${statements.map(node => printer.printNode(ts.EmitHint.Unspecified, node, source)).join('\n')}\n`
|
||||
}
|
||||
|
||||
export function checkPluginEditorDeclaration(code: string, core: string, consumer = '', compiler: typeof ts = ts) {
|
||||
const folder = fileURLToPath(new URL('../../refactor/.cache/plugin-editor-semantic/', import.meta.url))
|
||||
const sources = new Map([
|
||||
[path.join(folder, 'artplayer.d.ts'), core],
|
||||
[path.join(folder, 'plugin.d.ts'), code],
|
||||
[path.join(folder, 'consumer.ts'), consumer],
|
||||
])
|
||||
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs }
|
||||
const host = compiler.createCompilerHost(options)
|
||||
const getSourceFile = host.getSourceFile.bind(host)
|
||||
host.getSourceFile = (file, version, onError, create) => sources.has(path.resolve(file))
|
||||
? compiler.createSourceFile(file, sources.get(path.resolve(file))!, version, true)
|
||||
: getSourceFile(file, version, onError, create)
|
||||
const program = compiler.createProgram([...sources.keys()], options, host)
|
||||
for (const file of program.getSourceFiles())
|
||||
assert(sources.has(path.resolve(file.fileName)) || program.isSourceFileDefaultLibrary(file), `Plugin editor types escaped the standalone bundle: ${file.fileName}`)
|
||||
return compiler.getPreEmitDiagnostics(program).map(diagnostic => ({ code: diagnostic.code, message: compiler.flattenDiagnosticMessageText(diagnostic.messageText, '\n') }))
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import ts from 'typescript'
|
||||
|
||||
export function parseDeclaration(code: string, file = 'plugin.d.ts'): ts.SourceFile {
|
||||
const source = ts.createSourceFile(file, code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
const options: ts.CompilerOptions = { noLib: true, noResolve: true, types: [] }
|
||||
const host = ts.createCompilerHost(options)
|
||||
host.getSourceFile = name => name === file ? source : undefined
|
||||
const program = ts.createProgram([file], options, host)
|
||||
assert.equal(program.getSyntacticDiagnostics(source).length, 0, 'Invalid plugin declaration syntax')
|
||||
return source
|
||||
}
|
||||
|
||||
export function exportedDefinition(node: ts.Statement): ts.Statement {
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isClassDeclaration(node)
|
||||
|| ts.isModuleDeclaration(node) || ts.isEnumDeclaration(node), 'Unsupported SDK declaration kind')
|
||||
return ts.factory.replaceModifiers(node, [ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)])
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import ts from 'typescript'
|
||||
|
||||
export function checkStandaloneDeclarations(files: Map<string, string>, compiler: typeof ts = ts) {
|
||||
const folder = path.resolve(fileURLToPath(new URL('../../refactor/.cache/editor-check/', import.meta.url)))
|
||||
const sources = new Map([...files].map(([file, code]) => [path.join(folder, file), code]))
|
||||
const options: ts.CompilerOptions = { strict: true, noEmit: true, skipLibCheck: false, types: [], target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs }
|
||||
const host = compiler.createCompilerHost(options)
|
||||
const getSourceFile = host.getSourceFile.bind(host)
|
||||
const exists = host.fileExists.bind(host)
|
||||
const directoryExists = host.directoryExists?.bind(host)
|
||||
host.fileExists = file => sources.has(path.resolve(file)) || exists(file)
|
||||
host.directoryExists = directory => path.resolve(directory) === folder || !!directoryExists?.(directory)
|
||||
host.getSourceFile = (file, version, onError, create) => {
|
||||
const code = sources.get(path.resolve(file))
|
||||
return code === undefined ? getSourceFile(file, version, onError, create) : compiler.createSourceFile(file, code, version, true)
|
||||
}
|
||||
const program = compiler.createProgram([...sources.keys()], options, host)
|
||||
for (const file of program.getSourceFiles())
|
||||
assert(sources.has(path.resolve(file.fileName)) || program.isSourceFileDefaultLibrary(file), `Editor types escaped the standalone bundle: ${file.fileName}`)
|
||||
return compiler.getPreEmitDiagnostics(program).map(diagnostic => ({ code: diagnostic.code, file: diagnostic.file && path.basename(diagnostic.file.fileName), message: compiler.flattenDiagnosticMessageText(diagnostic.messageText, '\n') }))
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
// Types only: the editor does not fetch or execute the advertising SDK.
|
||||
export type { Player, PlayerOptions } from '@glomex/vast-ima-player'
|
||||
+2
-143
@@ -1,143 +1,2 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { createRequire } from 'node:module'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import { generateDtsBundle } from 'dts-bundle-generator'
|
||||
import ts from 'typescript'
|
||||
import compat from 'typescript-compat'
|
||||
|
||||
const root = fileURLToPath(new URL('../', import.meta.url))
|
||||
const factory = ts.factory
|
||||
|
||||
/** Put flattened definitions in a private scope so public aliases cannot refer to themselves. */
|
||||
export function asGlobalDeclaration(code, globalName) {
|
||||
assert(/^[A-Z_$][\w$]*$/i.test(globalName), 'Invalid editor global name')
|
||||
const source = ts.createSourceFile('bundle.d.ts', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
const exports = new Map()
|
||||
const declarations = new Map()
|
||||
const definitions = []
|
||||
for (const node of source.statements) {
|
||||
if (ts.isExportDeclaration(node)) {
|
||||
assert(!node.moduleSpecifier && node.exportClause && ts.isNamedExports(node.exportClause), 'Editor bundle must contain no unresolved exports')
|
||||
for (const item of node.exportClause.elements)
|
||||
exports.set(item.name.text, (item.propertyName || item.name).text)
|
||||
continue
|
||||
}
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isClassDeclaration(node), `Unsupported editor declaration: ${ts.SyntaxKind[node.kind]}`)
|
||||
assert(node.name, 'Editor definitions must be named')
|
||||
const name = node.name.text
|
||||
assert(!declarations.has(name), `Duplicate bundled declaration: ${name}`)
|
||||
declarations.set(name, node)
|
||||
if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword))
|
||||
exports.set(name, name)
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
}
|
||||
const defaultName = exports.get('default')
|
||||
assert(defaultName && ts.isClassDeclaration(declarations.get(defaultName)), 'Core editor requires the actual default constructor class')
|
||||
const definitionName = `${globalName}Definitions`
|
||||
assert(!declarations.has(definitionName), 'Editor definition namespace collides with source')
|
||||
const qualified = name => factory.createQualifiedName(factory.createIdentifier(definitionName), factory.createIdentifier(name))
|
||||
const aliases = []
|
||||
for (const [name, local] of exports) {
|
||||
if (name === 'default')
|
||||
continue
|
||||
const declaration = declarations.get(local)
|
||||
assert(declaration, `Missing bundled export: ${local}`)
|
||||
const parameters = declaration.typeParameters
|
||||
aliases.push(factory.createTypeAliasDeclaration(
|
||||
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
||||
name,
|
||||
parameters,
|
||||
factory.createTypeReferenceNode(qualified(local), parameters?.map(parameter => factory.createTypeReferenceNode(parameter.name))),
|
||||
))
|
||||
}
|
||||
const namespace = (name, nodes) => factory.createModuleDeclaration(
|
||||
[factory.createModifier(ts.SyntaxKind.DeclareKeyword)],
|
||||
factory.createIdentifier(name),
|
||||
factory.createModuleBlock(nodes),
|
||||
ts.NodeFlags.Namespace,
|
||||
)
|
||||
const statements = [
|
||||
namespace(definitionName, definitions),
|
||||
factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createVariableDeclarationList([
|
||||
factory.createVariableDeclaration(globalName, undefined, factory.createTypeQueryNode(qualified(defaultName))),
|
||||
], ts.NodeFlags.Const)),
|
||||
factory.createTypeAliasDeclaration(undefined, globalName, undefined, factory.createTypeReferenceNode(qualified(defaultName))),
|
||||
namespace(globalName, aliases),
|
||||
factory.createExportAssignment(undefined, true, factory.createIdentifier(globalName)),
|
||||
factory.createNamespaceExportDeclaration(factory.createIdentifier(globalName)),
|
||||
]
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||
return `// Generated from packages/artplayer/public/artplayer.ts by yarn build:ts. Do not edit.\n/* eslint-disable ts/no-redeclare, ts/no-namespace -- UMD constructor and named types share the global export. */\n${printer.printFile(factory.updateSourceFile(source, statements))}`
|
||||
}
|
||||
|
||||
export function generateCoreEditorDeclaration() {
|
||||
const require = createRequire(import.meta.url)
|
||||
const bundlerRequire = createRequire(require.resolve('dts-bundle-generator'))
|
||||
assert.equal(bundlerRequire('typescript'), ts, 'Editor bundler must use the pinned workspace compiler')
|
||||
const [code] = generateDtsBundle([{
|
||||
filePath: path.join(root, 'packages/artplayer/public/artplayer.ts'),
|
||||
output: { exportReferencedTypes: false, noBanner: true },
|
||||
}], { preferredConfigPath: path.join(root, 'scripts/tsconfig.editor.json') })
|
||||
const declaration = asGlobalDeclaration(code, 'Artplayer')
|
||||
for (const compiler of [ts, compat])
|
||||
assert.deepEqual(checkCoreEditorDeclaration(declaration, compiler), [], `Invalid editor declaration: TS ${compiler.version}`)
|
||||
return declaration
|
||||
}
|
||||
|
||||
export function checkCoreEditorDeclaration(code, compiler = ts) {
|
||||
const folder = path.join(root, 'refactor/.cache/editor-semantic')
|
||||
const declaration = path.join(folder, 'artplayer.d.ts')
|
||||
const sources = new Map([
|
||||
[declaration, code],
|
||||
[path.join(folder, 'global.ts'), `
|
||||
const option: Artplayer.OptionInput = { container: '#player' }
|
||||
const player: Artplayer = new Artplayer(option, function (art) {
|
||||
const same: Artplayer = this
|
||||
const other: Artplayer = art
|
||||
void [same, other]
|
||||
})
|
||||
const factory: Artplayer.PluginFactory<Artplayer, { name: string }> = function (art) {
|
||||
return { name: String(art.id + this.id) }
|
||||
}
|
||||
const plugins: Promise<Artplayer.Plugins> = player.plugins.add(factory)
|
||||
const emitter: Artplayer.Emitter<{ value: [number] }> = new Artplayer.Emitter()
|
||||
emitter.on('value', count => count.toFixed()).emit('value', 2)
|
||||
const language: NonNullable<Artplayer.I18n['en']> = { Play: 'Play' }
|
||||
const configuration: Artplayer.Config = Artplayer.config
|
||||
// @ts-expect-error Private flattened definitions must not leak into the editor global scope.
|
||||
const leaked: ArtplayerDefinitions.Config = Artplayer.config
|
||||
// @ts-expect-error Required container is not optional.
|
||||
new Artplayer({ url: '' })
|
||||
// @ts-expect-error Named aliases must not degrade to any through circular definitions.
|
||||
const invalidOption: Artplayer.Option = { container: 123, url: '' }
|
||||
// @ts-expect-error Plugin callback results retain the selected result type.
|
||||
const invalidFactory: Artplayer.PluginFactory<Artplayer, number> = () => 'bad'
|
||||
// @ts-expect-error Generic event payloads stay checked.
|
||||
emitter.emit('value', 'bad')
|
||||
void [plugins, language, configuration, invalidOption, invalidFactory, leaked]
|
||||
`],
|
||||
[path.join(folder, 'module.ts'), `
|
||||
import Player = require('./artplayer')
|
||||
const player: Player = new Player({ container: '#player' })
|
||||
const option: Player.OptionInput = { container: '#player' }
|
||||
// @ts-expect-error The UMD export is the constructor, not a default wrapper object.
|
||||
Player.default
|
||||
void [player, option]
|
||||
`],
|
||||
])
|
||||
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs }
|
||||
const host = compiler.createCompilerHost(options)
|
||||
const getSourceFile = host.getSourceFile.bind(host)
|
||||
const exists = host.fileExists.bind(host)
|
||||
const directoryExists = host.directoryExists.bind(host)
|
||||
host.fileExists = file => sources.has(path.resolve(file)) || exists(file)
|
||||
host.directoryExists = directory => path.resolve(directory) === folder || directoryExists(directory)
|
||||
host.getSourceFile = (file, version, onError, create) => sources.has(path.resolve(file))
|
||||
? compiler.createSourceFile(file, sources.get(path.resolve(file)), version, true)
|
||||
: getSourceFile(file, version, onError, create)
|
||||
const program = compiler.createProgram([...sources.keys()], options, host)
|
||||
for (const file of program.getSourceFiles())
|
||||
assert(sources.has(path.resolve(file.fileName)) || program.isSourceFileDefaultLibrary(file), `Editor types escaped the standalone bundle: ${file.fileName}`)
|
||||
return compiler.getPreEmitDiagnostics(program).map(diagnostic => ({ code: diagnostic.code, message: compiler.flattenDiagnosticMessageText(diagnostic.messageText, '\n') }))
|
||||
}
|
||||
// Preserve existing tooling imports while implementation lives in checked TypeScript.
|
||||
export { asGlobalDeclaration, checkCoreEditorDeclaration, generateCoreEditorDeclaration } from './editor-declarations/core.ts'
|
||||
@@ -1,160 +1,2 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import path from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import ts from 'typescript'
|
||||
|
||||
// Migrate each package explicitly; unknown imports/exports must not disappear silently.
|
||||
export function generatePluginEditorDeclaration(code, name, localTypes = {}) {
|
||||
assert(/^[a-z_$][\w$]*$/i.test(name), 'Invalid plugin global')
|
||||
let source = ts.createSourceFile('plugin.d.ts', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
assert.equal(source.parseDiagnostics.length, 0, 'Invalid plugin declaration syntax')
|
||||
const expanded = []
|
||||
for (const node of source.statements) {
|
||||
if (!ts.isExportDeclaration(node) || !node.moduleSpecifier) {
|
||||
expanded.push(node)
|
||||
continue
|
||||
}
|
||||
assert(node.isTypeOnly, 'Unsupported plugin editor declaration: runtime re-export')
|
||||
const dependency = localTypes[node.moduleSpecifier.text]
|
||||
assert(typeof dependency === 'string' && node.exportClause && ts.isNamedExports(node.exportClause), 'Unsupported editor type re-export')
|
||||
const names = node.exportClause.elements.map((item) => {
|
||||
assert(!item.propertyName, 'Renamed editor type re-export is unsupported')
|
||||
return item.name.text
|
||||
})
|
||||
const types = ts.createSourceFile('dependency.d.ts', dependency, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
assert.equal(types.parseDiagnostics.length, 0)
|
||||
const definitions = types.statements.filter(item => !ts.isImportDeclaration(item))
|
||||
assert(definitions.every(item => ts.isInterfaceDeclaration(item) || ts.isTypeAliasDeclaration(item)), 'Editor dependencies must contain only types')
|
||||
assert.deepEqual(definitions.map(item => item.name.text).sort(), names.sort(), 'Editor re-export must explicitly cover its local type definitions')
|
||||
expanded.push(...types.statements)
|
||||
}
|
||||
// Reparse combined statements so comments and text positions belong to one file.
|
||||
source = ts.createSourceFile('plugin.d.ts', expanded.map(node => ts.createPrinter().printNode(ts.EmitHint.Unspecified, node, node.getSourceFile())).join('\n'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
|
||||
if (source.statements.some(node => ts.isExportAssignment(node) && node.isExportEquals))
|
||||
return generateCommonJSPluginEditor(source, name)
|
||||
const factory = ts.factory
|
||||
const definitions = []
|
||||
const aliases = []
|
||||
const internal = `${name}Definitions`
|
||||
let exported = false
|
||||
let callable = false
|
||||
let classExport = false
|
||||
for (const node of source.statements) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
assert(node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported plugin editor import')
|
||||
continue
|
||||
}
|
||||
if (ts.isExportAssignment(node)) {
|
||||
assert(!node.isExportEquals && ts.isIdentifier(node.expression) && node.expression.text === name, 'Unexpected plugin default export')
|
||||
exported = true
|
||||
continue
|
||||
}
|
||||
if (ts.isVariableStatement(node)) {
|
||||
const values = node.declarationList.declarations
|
||||
assert(values.length === 1 && values[0].name.text === name && ts.isFunctionTypeNode(values[0].type), 'Unexpected plugin callable variable')
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
callable = true
|
||||
continue
|
||||
}
|
||||
assert(ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node), 'Unsupported plugin editor declaration')
|
||||
assert(node.name && node.name.text !== internal, 'Invalid plugin declaration name')
|
||||
definitions.push(factory.replaceModifiers(node, [factory.createModifier(ts.SyntaxKind.ExportKeyword)]))
|
||||
if (ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) {
|
||||
assert.equal(node.name.text, name, 'Unexpected plugin callable')
|
||||
callable = true
|
||||
classExport = ts.isClassDeclaration(node)
|
||||
continue
|
||||
}
|
||||
if (node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
||||
aliases.push(factory.createTypeAliasDeclaration(
|
||||
[factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
||||
node.name,
|
||||
node.typeParameters,
|
||||
factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(internal), node.name), node.typeParameters?.map(parameter => factory.createTypeReferenceNode(parameter.name))),
|
||||
))
|
||||
}
|
||||
}
|
||||
assert(exported && callable, 'Plugin editor requires a default function or class')
|
||||
const namespace = (identifier, statements) => factory.createModuleDeclaration([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createIdentifier(identifier), factory.createModuleBlock(statements), ts.NodeFlags.Namespace)
|
||||
const statements = [
|
||||
namespace(internal, definitions),
|
||||
factory.createVariableStatement([factory.createModifier(ts.SyntaxKind.DeclareKeyword)], factory.createVariableDeclarationList([
|
||||
factory.createVariableDeclaration(name, undefined, factory.createTypeQueryNode(factory.createQualifiedName(factory.createIdentifier(internal), factory.createIdentifier(name)))),
|
||||
], ts.NodeFlags.Const)),
|
||||
...(classExport ? [factory.createTypeAliasDeclaration(undefined, name, undefined, factory.createTypeReferenceNode(factory.createQualifiedName(factory.createIdentifier(internal), factory.createIdentifier(name))))] : []),
|
||||
namespace(name, aliases),
|
||||
factory.createExportAssignment(undefined, true, factory.createIdentifier(name)),
|
||||
factory.createNamespaceExportDeclaration(factory.createIdentifier(name)),
|
||||
]
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||
return `// Generated from the package public declaration by yarn build:ts. Do not edit.\n/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */\n${statements.map(node => printer.printNode(ts.EmitHint.Unspecified, node, source)).join('\n')}\n`
|
||||
}
|
||||
|
||||
function generateCommonJSPluginEditor(source, name) {
|
||||
const statements = []
|
||||
let namespace = false
|
||||
let callable = false
|
||||
let exported = false
|
||||
let global = false
|
||||
let classExport = false
|
||||
for (const node of source.statements) {
|
||||
if (ts.isImportDeclaration(node)) {
|
||||
assert(node.importClause?.isTypeOnly && !node.importClause.namedBindings && node.importClause.name?.text === 'Artplayer' && node.moduleSpecifier.text === 'artplayer', 'Unsupported CommonJS plugin editor import')
|
||||
continue
|
||||
}
|
||||
if (ts.isModuleDeclaration(node)) {
|
||||
assert.equal(node.name.text, name, 'Unexpected plugin namespace')
|
||||
assert(node.body && ts.isModuleBlock(node.body) && node.body.statements.every(item => ts.isInterfaceDeclaration(item) || ts.isTypeAliasDeclaration(item)), 'Editor namespace must contain only public type declarations')
|
||||
namespace = true
|
||||
}
|
||||
else if (ts.isClassDeclaration(node)) {
|
||||
assert.equal(node.name?.text, name, 'Unexpected CommonJS editor class')
|
||||
callable = true
|
||||
classExport = true
|
||||
}
|
||||
else if (ts.isVariableStatement(node)) {
|
||||
const definitions = node.declarationList.declarations
|
||||
assert.equal(definitions.length, 1)
|
||||
const definition = definitions[0]
|
||||
assert.equal(definition.name.text, name)
|
||||
assert(ts.isTypeReferenceNode(definition.type) && ts.isQualifiedName(definition.type.typeName)
|
||||
&& definition.type.typeName.left.text === name && definition.type.typeName.right.text === 'Factory', 'Editor export must use its public Factory interface')
|
||||
callable = true
|
||||
}
|
||||
else if (ts.isExportAssignment(node)) {
|
||||
assert(node.isExportEquals && node.expression.text === name, 'Unexpected CommonJS plugin export')
|
||||
exported = true
|
||||
}
|
||||
else if (ts.isNamespaceExportDeclaration(node)) {
|
||||
assert.equal(node.name.text, name)
|
||||
global = true
|
||||
}
|
||||
else {
|
||||
assert.fail('Unsupported CommonJS plugin editor declaration')
|
||||
}
|
||||
statements.push(node)
|
||||
}
|
||||
assert(namespace && callable && exported && global, 'Incomplete CommonJS plugin editor declaration')
|
||||
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed })
|
||||
const bridge = classExport ? '' : '/* eslint-disable ts/no-redeclare -- Callable and public type namespace intentionally merge. */\n'
|
||||
return `// Generated from the package public declaration by yarn build:ts. Do not edit.\n${bridge}${statements.map(node => printer.printNode(ts.EmitHint.Unspecified, node, source)).join('\n')}\n`
|
||||
}
|
||||
|
||||
export function checkPluginEditorDeclaration(code, core, consumer = '', compiler = ts) {
|
||||
const folder = fileURLToPath(new URL('../refactor/.cache/plugin-editor-semantic/', import.meta.url))
|
||||
const sources = new Map([
|
||||
[path.join(folder, 'artplayer.d.ts'), core],
|
||||
[path.join(folder, 'plugin.d.ts'), code],
|
||||
[path.join(folder, 'consumer.ts'), consumer],
|
||||
])
|
||||
const options = { strict: true, noEmit: true, skipLibCheck: false, types: [], target: compiler.ScriptTarget.ES2020, lib: ['lib.es2020.d.ts', 'lib.dom.d.ts'], module: compiler.ModuleKind.CommonJS, moduleResolution: compiler.ModuleResolutionKind.NodeJs }
|
||||
const host = compiler.createCompilerHost(options)
|
||||
const getSourceFile = host.getSourceFile.bind(host)
|
||||
host.getSourceFile = (file, version, onError, create) => sources.has(path.resolve(file))
|
||||
? compiler.createSourceFile(file, sources.get(path.resolve(file)), version, true)
|
||||
: getSourceFile(file, version, onError, create)
|
||||
const program = compiler.createProgram([...sources.keys()], options, host)
|
||||
for (const file of program.getSourceFiles())
|
||||
assert(sources.has(path.resolve(file.fileName)) || program.isSourceFileDefaultLibrary(file), `Plugin editor types escaped the standalone bundle: ${file.fileName}`)
|
||||
return compiler.getPreEmitDiagnostics(program).map(diagnostic => ({ code: diagnostic.code, message: compiler.flattenDiagnosticMessageText(diagnostic.messageText, '\n') }))
|
||||
}
|
||||
// Preserve existing tooling imports while implementation lives in checked TypeScript.
|
||||
export { checkPluginEditorDeclaration, generatePluginEditorDeclaration } from './editor-declarations/plugin.ts'
|
||||
@@ -1,10 +1,23 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2021", "DOM", "DOM.Iterable"],
|
||||
"types": ["node"],
|
||||
"lib": [
|
||||
"ES2021",
|
||||
"DOM",
|
||||
"DOM.Iterable"
|
||||
],
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"allowImportingTsExtensions": true,
|
||||
"checkJs": true
|
||||
},
|
||||
"include": ["docs-smoke/**/*.ts", "build-test.js"]
|
||||
"include": [
|
||||
"docs-smoke/**/*.ts",
|
||||
"build-test.js",
|
||||
"build-ts.js",
|
||||
"editor-declarations/**/*.ts",
|
||||
"editor-types.mjs",
|
||||
"plugin-editor-types.mjs"
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
# Tests and fixture ownership
|
||||
|
||||
Editor tooling lives in `scripts/editor-declarations/`; see its README.
|
||||
`test/editor-types.test.js` checks standalone globals and module consumers with
|
||||
current/old compilers, Chapter/VAST regressions, generated files and library-list
|
||||
failures. Package baseline tests continue to exercise the old MJS import paths.
|
||||
|
||||
Use the pinned Node/Yarn toolchain from `../refactor/toolchain-setup.md`.
|
||||
|
||||
`yarn build:test` generates deterministic documentation readiness smoke and its
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# Browser regression entry
|
||||
|
||||
`editor-declarations.spec.js` loads the repository Monaco with the 22 declarations
|
||||
actually listed in `common.js`, checks positive/negative consumers and runs emitted
|
||||
Chapter code through ready/destroy with controlled media. VAST coverage is types
|
||||
only, not advertising SDK execution. The unreferenced legacy WebSR declaration
|
||||
asset is preserved; this test follows the actual editor's library list.
|
||||
|
||||
`docs-smoke.spec.js` verifies the documentation runner in three engines with
|
||||
actual core/media, controlled failures and three selected generated snippets.
|
||||
It checks pending readiness beyond the former 100ms timer, returned/unhandled
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import fs from 'node:fs'
|
||||
import { hash } from '../../refactor/scripts/releases.mjs'
|
||||
import { expect, test } from './fixtures.js'
|
||||
|
||||
test('Monaco checks all editor declarations together and runs the Chapter consumer', async ({ page }, testInfo) => {
|
||||
const common = fs.readFileSync('docs/assets/js/common.js', 'utf8')
|
||||
const list = common.match(/let libUris = \[([\s\S]*?)\]/)?.[1] || ''
|
||||
const names = [...list.matchAll(/'\.\/assets\/ts\/([^']+\.d\.ts)'/g)].map(match => match[1])
|
||||
expect(names).toHaveLength(22)
|
||||
await testInfo.attach('editor-declaration-inputs', { contentType: 'application/json', body: JSON.stringify(Object.fromEntries(names.map(name => [name, hash(fs.readFileSync(`docs/assets/ts/${name}`))]))) })
|
||||
await page.goto('/test/player.html?core=candidate&chapter=candidate')
|
||||
await page.addScriptTag({ url: '/assets/js/vs/loader.js' })
|
||||
const result = await page.evaluate(async (names) => {
|
||||
window.require.config({ paths: { vs: '/assets/js/vs' } })
|
||||
await new Promise((resolve, reject) => window.require(['vs/editor/editor.main'], resolve, reject))
|
||||
const api = window.monaco
|
||||
const types = api.languages.typescript
|
||||
types.typescriptDefaults.setCompilerOptions({ target: types.ScriptTarget.ES2020, strict: true, skipLibCheck: false, noEmit: false, types: [], allowNonTsExtensions: true })
|
||||
const libraries = await Promise.all(names.map(async (name) => {
|
||||
const source = await (await fetch(`/assets/ts/${name}`)).text()
|
||||
const uri = `file:///${name}`
|
||||
return { uri, handle: types.typescriptDefaults.addExtraLib(source, uri) }
|
||||
}))
|
||||
const model = api.editor.createModel(`
|
||||
const chapters: artplayerPluginChapter.Chapters = [{ start: 0, end: 2, title: 'Intro' }];
|
||||
const player = new Artplayer({ container: '.player', url: '/test/pattern.mp4', muted: true, plugins: [artplayerPluginChapter({ chapters })] });
|
||||
const chapter = player.plugins.artplayerPluginChapter as artplayerPluginChapter.Result;
|
||||
chapter.update({ chapters: [{ start: 0, end: 1, title: 'Updated' }] });
|
||||
const adOption: artplayerPluginVast.ArtplayerPluginVastOption = context => {
|
||||
const volume: number = context.init().volume;
|
||||
context.playerOptions.autoResize = true;
|
||||
return Promise.resolve();
|
||||
};
|
||||
`, 'typescript', api.Uri.parse('file:///editor-consumer.ts'))
|
||||
const invalid = api.editor.createModel(`
|
||||
artplayerPluginVast(context => { context.init().volume = 'loud'; context.playerOptions.autoResize = 'yes'; });
|
||||
artplayerPluginChapter({ chapters: [{ start: '0', end: 2, title: '' }] });
|
||||
`, 'typescript', api.Uri.parse('file:///editor-invalid.ts'))
|
||||
try {
|
||||
const worker = await (await types.getTypeScriptWorker())(model.uri, invalid.uri)
|
||||
const syntax = await worker.getSyntacticDiagnostics(model.uri.toString())
|
||||
const semantic = await worker.getSemanticDiagnostics(model.uri.toString())
|
||||
const declarations = (await Promise.all(libraries.map(lib => worker.getSemanticDiagnostics(lib.uri)))).flat()
|
||||
const bad = (await worker.getSemanticDiagnostics(invalid.uri.toString())).map(item => item.code)
|
||||
if (syntax.length || semantic.length || declarations.length)
|
||||
return { syntax, semantic, declarations, bad }
|
||||
const output = await worker.getEmitOutput(model.uri.toString())
|
||||
const script = output.outputFiles.find(file => file.name.endsWith('.js'))
|
||||
if (!script)
|
||||
throw new Error('Monaco did not emit the consumer')
|
||||
// eslint-disable-next-line no-new-func -- Execute the actual editor output with local controlled media.
|
||||
const player = new Function(`${script.text}\nreturn player`)()
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
player.on('ready', resolve)
|
||||
player.on('error', reject)
|
||||
})
|
||||
const name = player.plugins.artplayerPluginChapter.name
|
||||
const ready = player.isReady
|
||||
player.destroy(true)
|
||||
return { syntax, semantic, declarations, bad, name, ready, instances: window.Artplayer.instances.length }
|
||||
}
|
||||
finally {
|
||||
if (!player.isDestroy)
|
||||
player.destroy(true)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
model.dispose()
|
||||
invalid.dispose()
|
||||
for (const library of libraries) library.handle.dispose()
|
||||
}
|
||||
}, names)
|
||||
await testInfo.attach('editor-declaration-result', { contentType: 'application/json', body: JSON.stringify(result) })
|
||||
expect(result.syntax).toEqual([])
|
||||
expect(result.semantic).toEqual([])
|
||||
expect(result.declarations).toEqual([])
|
||||
expect(result.bad).toEqual([2322, 2322, 2322])
|
||||
expect(result.name).toBe('artplayerPluginChapter')
|
||||
expect(result.ready).toBe(true)
|
||||
expect(result.instances).toBe(0)
|
||||
})
|
||||
@@ -4,6 +4,9 @@ import fs from 'node:fs'
|
||||
import { test } from 'node:test'
|
||||
import { ESLint } from 'eslint'
|
||||
import compat from 'typescript-compat'
|
||||
import { vastSdkDeclarations } from '../scripts/editor-declarations/dependencies.ts'
|
||||
import { editorLibUris, generateEditorDeclarations } from '../scripts/editor-declarations/generate.ts'
|
||||
import { checkStandaloneDeclarations } from '../scripts/editor-declarations/validation.ts'
|
||||
import { asGlobalDeclaration, checkCoreEditorDeclaration, generateCoreEditorDeclaration } from '../scripts/editor-types.mjs'
|
||||
import { checkPluginEditorDeclaration, generatePluginEditorDeclaration } from '../scripts/plugin-editor-types.mjs'
|
||||
|
||||
@@ -21,6 +24,74 @@ test('editor declarations are reproducible, standalone and preserve constructor/
|
||||
assert.throws(() => asGlobalDeclaration('export { default } from "./missing"', 'Artplayer'), /unresolved exports/)
|
||||
})
|
||||
|
||||
test('Chapter and VAST editor consumers preserve SDK types, optional Window hook and named results', () => {
|
||||
const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8')
|
||||
const generated = new Map([['artplayer.d.ts', core]])
|
||||
for (const [suffix, global] of [['chapter', 'artplayerPluginChapter'], ['vast', 'artplayerPluginVast']]) {
|
||||
const source = fs.readFileSync(`packages/artplayer-plugin-${suffix}/types/artplayer-plugin-${suffix}.d.ts`, 'utf8')
|
||||
const old = `${source.replace(/^import.*$/gim, '')}\nexport = ${global};\nexport as namespace ${global};\n`
|
||||
const diagnostics = checkPluginEditorDeclaration(old, core)
|
||||
assert(diagnostics.some(item => item.code === 2309))
|
||||
if (suffix === 'vast')
|
||||
assert(diagnostics.some(item => item.code === 2304 && item.message.includes('Player')))
|
||||
generated.set(`${suffix}.d.ts`, generatePluginEditorDeclaration(source, global, {}, suffix === 'vast' ? vastSdkDeclarations() : []))
|
||||
}
|
||||
const consumer = `
|
||||
import chapter = require('./chapter');
|
||||
import vast = require('./vast');
|
||||
declare const art: Artplayer;
|
||||
const chapters: chapter.Chapters = [{ start: 0, end: 10, title: 'Intro' }];
|
||||
const result: chapter.Result = chapter({ chapters })(art);
|
||||
result.update({ chapters: [] });
|
||||
const option: vast.ArtplayerPluginVastOption = async context => {
|
||||
const player = context.init();
|
||||
const volume: number = player.volume;
|
||||
player.volume = 0.5;
|
||||
player.pause();
|
||||
player.play();
|
||||
context.playUrl('ad.xml', { oldUntypedConfig: true });
|
||||
// @ts-expect-error SDK numeric property remains checked.
|
||||
player.volume = 'loud';
|
||||
// @ts-expect-error SDK methods must not degrade to any.
|
||||
player.missingMethod();
|
||||
// @ts-expect-error Private SDK implementation stays private.
|
||||
player._setupIma();
|
||||
void volume;
|
||||
};
|
||||
const instance: vast.ArtplayerPluginVastInstance = vast(option)(art);
|
||||
const windowFactory: typeof vast | undefined = window.artplayerPluginVast;
|
||||
// @ts-expect-error Historical required callback is still required.
|
||||
vast();
|
||||
// @ts-expect-error Chapter timestamps stay numeric.
|
||||
chapter({ chapters: [{ start: '0', end: 1, title: '' }] });
|
||||
// @ts-expect-error SDK internals are private to the declaration module.
|
||||
declare const leaked: artplayerPluginVastDefinitions.Player;
|
||||
void [result, instance, windowFactory, leaked];
|
||||
`
|
||||
generated.set('global.ts', 'declare const globalArt: Artplayer; const globalResult: artplayerPluginChapter.Result = artplayerPluginChapter()(globalArt);')
|
||||
for (const compiler of [undefined, compat]) {
|
||||
generated.set('consumer.ts', consumer)
|
||||
assert.deepEqual(checkStandaloneDeclarations(generated, compiler), [])
|
||||
generated.set('consumer.ts', consumer.replaceAll(/\/\/ @ts-expect-error[^\n]*\n/g, ''))
|
||||
const errors = checkStandaloneDeclarations(generated, compiler)
|
||||
assert.equal(errors.length, 6, 'Every intentional misuse must remain rejected')
|
||||
}
|
||||
})
|
||||
|
||||
test('all editor outputs are generated and checked together without modifying source declarations', async () => {
|
||||
const outputs = await generateEditorDeclarations()
|
||||
assert.equal([...outputs.keys()].filter(file => file.endsWith('.d.ts')).length, 22)
|
||||
for (const [file, code] of outputs)
|
||||
assert.equal(fs.readFileSync(file, 'utf8').replaceAll('\r\n', '\n'), code.replaceAll('\r\n', '\n'), `Stale editor output: ${file}`)
|
||||
await assert.rejects(generateEditorDeclarations(['missing-plugin']), /Unknown declaration package/)
|
||||
await assert.rejects(generateEditorDeclarations(['artplayer-plugin-chapter', 'artplayer-plugin-chapter']), /Duplicate/)
|
||||
const source = 'const note = \'libUris\'; let libUris = [\'old\']; const untouched = 1'
|
||||
assert.equal(editorLibUris(source, ['chapter.d.ts']), 'const note = \'libUris\'; let libUris = [\n \'./assets/ts/chapter.d.ts\',\n ]; const untouched = 1')
|
||||
assert.throws(() => editorLibUris('const unrelated = []', []), /exactly one/)
|
||||
assert.throws(() => editorLibUris('let libUris = []; function x() { let libUris = [] }', []), /exactly one/)
|
||||
assert.throws(() => editorLibUris('let libUris = fetch()', []), /array initializer/)
|
||||
})
|
||||
|
||||
test('ASR editor generation supports named types without mixing default and export assignment', async () => {
|
||||
const source = fs.readFileSync('packages/artplayer-plugin-asr/types/artplayer-plugin-asr.d.ts', 'utf8')
|
||||
const core = fs.readFileSync('docs/assets/ts/artplayer.d.ts', 'utf8')
|
||||
|
||||
Reference in new issue
Block a user