fix(multiple-subtitles): [PKG-MULTI-SUB-04] preserve historical type shapes

This commit is contained in:
Harvey Zhao committed 2026-09-13 16:59:44 +08:00
1 parent 58d2c95d8e
commit 87cfcf5a6c
17 files changed
+223 -63

No files matched your search

@@ -7,7 +7,10 @@ Both methods return undefined. Root and legacy declarations retain the historica
`LegacyResult` for existing extraction and replacement-function consumers. The additive
`artplayer-plugin-multiple-subtitles/runtime` entry describes the actual `Promise<Result>`
and selection methods. It shares the root implementation, not another plugin instance.
The factory has a writable `.default` self alias for historical CommonJS access.
The factory has a writable `.default` self alias for historical CommonJS access. Only
`RuntimeFactory` requires that property; adding it to the historical root function type
would invalidate replacement functions. Root option and registration result remain exact
to npm 1.2.0; the runtime entry requires an option object but allows omitted `subtitles`.
## Current module boundaries
@@ -31,9 +34,11 @@ The factory has a writable `.default` self alias for historical CommonJS access.
The pinned upstream reference and full adaptation check are in
`../../refactor/baselines/multiple-subtitles-vendor/` and
`../../refactor/scripts/multiple-subtitles-vendor.mjs`.
- `types/artplayer-plugin-multiple-subtitles.d.ts` owns public data types and the historical
callable signature. Root/legacy `.d.mts` and `.d.cts` forward that signature; `runtime.d.*`
forwards the precise asynchronous factory. Classic resolution uses typesVersions.
- `types/artplayer-plugin-multiple-subtitles.d.ts` owns public data types and the latest
published function signature. Root/legacy exports use a types-first mapping to this file,
preserving the old NodeNext ESM namespace. Runtime `.d.mts` supplies a callable default;
runtime `.d.cts` and classic `.d.ts` use export-assignment with merged namespace type
aliases. Classic subpath resolution uses typesVersions. Root and runtime share JS files.
- `scripts/build-ts.js` generates the editor's global factory and named type namespace from
this declaration through the semantic generator. Never edit the generated editor file.
- `../../docs/assets/example/multiple.subtitles.js` demonstrates the real plugin name,
@@ -111,7 +116,15 @@ Public declaration tests check exact old extraction/replacement signatures, accu
types and negative uses with TS 5.9.3 and 4.3.5. The package test packs core and plugin, installs
outside the workspace and checks Node10/NodeNext/Bundler modes plus real CJS/ESM identities.
Historical 1.0.0/1.1.0 export-assignment declarations and 1.2.0 default-module declarations
disagree on raw `import = require` extraction. Task 04 retains that unresolved boundary;
default-import compatibility must not be presented as proof of every historical module form.
disagree on raw `import = require` extraction. The approved policy in
`../../refactor/type-compatibility-policy.md` and ADR-025 prioritizes latest npm 1.2.0.
Earlier consumers have the explicit runtime-entry migration in README; this is a declared
type migration, not proof that contradictory historical declarations all work unchanged.
Installed tests retain eight original NodeNext ESM direct-consumer diagnostics for both
1.2.0 and the candidate, while a namespace consumer remains valid. Frozen direct/default
CommonJS consumers preserve each old version's diagnostics as well. Candidate positives
check both factory-assignment directions and accurate asynchronous runtime methods in
seven compiler modes, including classic CommonJS without interop. Removing suppression
comments must reject all 16 invalid statements at their exact lines in every mode.
Tasks 05/06 still own complete core/device combinations and demo acceptance.
See `../../refactor/baselines/multiple-subtitles-contract.md` for exact historical differences.
@@ -8,7 +8,10 @@ Multiple subtitles plugin for ArtPlayer
## TypeScript
The root and `/legacy` type entries preserve historical parameter and return-type extraction.
The root and `/legacy` type entries preserve the latest published 1.2.0 function shape:
a required `{ subtitles: TrackOption[] }` argument and a synchronous `{ name: 'multipleSubtitles' }`
registration result. This includes parameter extraction and replacement-factory assignment in
both directions; the root factory type has no required `.default` property.
Registration has always been asynchronous. For accurate Promise and selection-method types,
use the additive runtime entry, which loads the same implementation:
@@ -27,6 +30,36 @@ result.reset()
The option object is required; `{}` means no tracks. `tracks()` clears the selection;
`reset()` restores all original tracks. Both methods return `void`. The existing `onParser`
field remains declared for compatibility but is not invoked by the implementation.
### Earlier declarations and module resolution
Versions 1.0.0 and 1.1.0 declared `export =`, whereas 1.2.0 declared a default export.
The root follows 1.2.0 under the approved [type compatibility policy](../../refactor/type-compatibility-policy.md).
For consumers migrating an earlier `import = require`, use the accurate runtime entry and
await registration:
```ts
import type Artplayer from 'artplayer'
import multipleSubtitles = require('artplayer-plugin-multiple-subtitles/runtime')
async function registerSubtitles(art: Artplayer) {
const result = await multipleSubtitles({ subtitles: [] })(art)
result.reset()
}
```
This `import = require` form works with classic Node resolution without `esModuleInterop`.
The runtime default import in the first example requires that flag in classic CommonJS;
NodeNext ESM and bundler resolution use its ESM declaration. Runtime types also expose the
existing writable `.default` self alias. JavaScript entrypoints and valid historical
`require('artplayer-plugin-multiple-subtitles').default(...)` calls remain supported.
The old 1.0.0/1.1.0 declaration allowed calling the raw `require` object, but its shipped
JavaScript did not; that mismatch is not a supported runtime contract.
NodeNext ESM intentionally retains the 1.2.0 root declaration's module namespace shape
(`import root from 'artplayer-plugin-multiple-subtitles'` exposes the declared factory as
`root.default`). It does not silently become a callable default type. Prefer the `/runtime`
default import for accurate native ESM calls; the same applies to `/legacy` declarations.
See [maintenance notes](ARCHITECTURE.md) for module responsibilities and validation commands.
## License
@@ -19,24 +19,14 @@
],
"exports": {
".": {
"import": {
"types": "./types/artplayer-plugin-multiple-subtitles.d.mts",
"default": "./dist/artplayer-plugin-multiple-subtitles.mjs"
},
"require": {
"types": "./types/artplayer-plugin-multiple-subtitles.d.cts",
"default": "./dist/artplayer-plugin-multiple-subtitles.js"
}
"types": "./types/artplayer-plugin-multiple-subtitles.d.ts",
"import": "./dist/artplayer-plugin-multiple-subtitles.mjs",
"require": "./dist/artplayer-plugin-multiple-subtitles.js"
},
"./legacy": {
"import": {
"types": "./types/artplayer-plugin-multiple-subtitles.d.mts",
"default": "./dist/artplayer-plugin-multiple-subtitles.legacy.js"
},
"require": {
"types": "./types/artplayer-plugin-multiple-subtitles.d.cts",
"default": "./dist/artplayer-plugin-multiple-subtitles.legacy.js"
}
"types": "./types/artplayer-plugin-multiple-subtitles.d.ts",
"import": "./dist/artplayer-plugin-multiple-subtitles.legacy.js",
"require": "./dist/artplayer-plugin-multiple-subtitles.legacy.js"
},
"./runtime": {
"import": {
@@ -1,5 +0,0 @@
import type { Factory } from './artplayer-plugin-multiple-subtitles.js'
declare const artplayerPluginMultipleSubtitles: Factory
export default artplayerPluginMultipleSubtitles
export type { Factory, LegacyResult, Option, Result, RuntimeFactory, RuntimeOption, TrackOption } from './artplayer-plugin-multiple-subtitles.js'
@@ -1,5 +0,0 @@
import type { Factory } from './artplayer-plugin-multiple-subtitles.js'
declare const artplayerPluginMultipleSubtitles: Factory
export default artplayerPluginMultipleSubtitles
export type { Factory, LegacyResult, Option, Result, RuntimeFactory, RuntimeOption, TrackOption } from './artplayer-plugin-multiple-subtitles.js'
@@ -1,4 +1,11 @@
import type { RuntimeFactory } from './artplayer-plugin-multiple-subtitles.js'
declare const artplayerPluginMultipleSubtitles: RuntimeFactory
// eslint-disable-next-line ts/no-redeclare -- Ambient merge exposes types on the CommonJS factory.
declare namespace artplayerPluginMultipleSubtitles {
type Result = import('./artplayer-plugin-multiple-subtitles.js').Result
type RuntimeFactory = import('./artplayer-plugin-multiple-subtitles.js').RuntimeFactory
type RuntimeOption = import('./artplayer-plugin-multiple-subtitles.js').RuntimeOption
type TrackOption = import('./artplayer-plugin-multiple-subtitles.js').TrackOption
}
export = artplayerPluginMultipleSubtitles
@@ -1,5 +1,11 @@
import type { RuntimeFactory } from './artplayer-plugin-multiple-subtitles.js'
declare const artplayerPluginMultipleSubtitles: RuntimeFactory
export default artplayerPluginMultipleSubtitles
export type { Result, RuntimeFactory, RuntimeOption, TrackOption } from './artplayer-plugin-multiple-subtitles.js'
// eslint-disable-next-line ts/no-redeclare -- Ambient merge exposes types on the CommonJS factory.
declare namespace artplayerPluginMultipleSubtitles {
type Result = import('./artplayer-plugin-multiple-subtitles.js').Result
type RuntimeFactory = import('./artplayer-plugin-multiple-subtitles.js').RuntimeFactory
type RuntimeOption = import('./artplayer-plugin-multiple-subtitles.js').RuntimeOption
type TrackOption = import('./artplayer-plugin-multiple-subtitles.js').TrackOption
}
export = artplayerPluginMultipleSubtitles