poi-plugin-item-improvement2-beta 1.0.26 → 1.0.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,27 +1,39 @@
1
- # Plugin-Item-Improvement
2
- Show improvable items of the day
3
- #### Usage
4
- Put the folder into /path/to/poi/resources/app/plugins.
1
+ # Plugin Item Improvement
5
2
 
6
- #### Data source
7
- The plugin makes use of equipment improvement data from [Akashi List](https://akashi-list.me/).
3
+ Poi plugin for viewing KanColle equipment improvement schedules, complete recipe routes, costs, and required materials.
8
4
 
9
- ## Publishing the beta package
5
+ ## Usage
10
6
 
11
- The beta package uses a separate npm package name while keeping the source tree on the official namespace.
7
+ Install the plugin through Poi, or place the package in Poi's plugin directory.
8
+
9
+ Improvement data and use-item assets are supplied by the local npm dependency `@sakura2333/kancolle-data`; the plugin does not download GitHub data at runtime.
10
+
11
+ ## Development
12
12
 
13
13
  ```bash
14
- npm run publish:beta:dry-run
15
- npm run publish:beta
14
+ npm ci --include=dev
15
+ npm test
16
+ npm pack --dry-run
16
17
  ```
17
18
 
18
- `publish:beta` temporarily replaces every runtime occurrence of
19
- `poi-plugin-item-improvement2-beta` with `poi-plugin-item-improvement2-beta-beta`, runs
20
- `npm publish`, and restores the original files even when publishing fails.
21
- Arguments after `--` are forwarded to `npm publish`.
19
+ The committed lockfile keeps the legacy Poi transpilation toolchain reproducible. CI tests both the locked minimum-compatible data package and the latest compatible data package.
22
20
 
23
- ## Data package
21
+ ## Publishing
22
+
23
+ Publish a compatible `@sakura2333/kancolle-data` release before publishing a plugin version that depends on it.
24
+
25
+ Official package:
26
+
27
+ ```bash
28
+ npm test
29
+ npm publish --registry=https://registry.npmjs.org/
30
+ ```
31
+
32
+ Beta package:
33
+
34
+ ```bash
35
+ npm run publish:beta:dry-run
36
+ npm run publish:beta
37
+ ```
24
38
 
25
- Improvement data and use-item PNG assets are supplied by the versioned npm dependency
26
- `@sakura2333/kancolle-data`. The plugin no longer downloads data from GitHub at runtime.
27
- Publish the data package before publishing a plugin version that depends on it.
39
+ The beta script temporarily changes the package and runtime namespace to `poi-plugin-item-improvement2-beta-beta`, publishes it, and restores the source tree even when publication fails.
package/i18n/en-US.json CHANGED
@@ -58,5 +58,6 @@
58
58
  "changelog_1_0_22_reopen_notes": "A What’s New button was added to the toolbar so release notes can be reopened at any time.",
59
59
  "changelog_1_0_21_stable_data": "Improvement information now loads and updates more reliably.",
60
60
  "changelog_1_0_21_separate_routes": "Improvement routes with different materials, costs, or upgrade targets are now shown in separate tables.",
61
- "changelog_1_0_21_tamanami_route": "Added Tamanami Kai Ni’s dedicated material route and kept it separate from the normal route."
61
+ "changelog_1_0_21_tamanami_route": "Added Tamanami Kai Ni’s dedicated material route and kept it separate from the normal route.",
62
+ "changelog_1_0_27_data_safety": "Improved data safety checks so incomplete or incompatible improvement information is rejected instead of being displayed incorrectly."
62
63
  }
package/i18n/ja-JP.json CHANGED
@@ -58,5 +58,6 @@
58
58
  "changelog_1_0_22_reopen_notes": "ツールバーに「更新履歴」ボタンを追加し、いつでも変更内容を確認できるようにしました。",
59
59
  "changelog_1_0_21_stable_data": "改修情報の読み込みと更新をより安定させました。",
60
60
  "changelog_1_0_21_separate_routes": "必要装備、資材、更新先が異なる改修ルートを別々の表で表示するようにしました。",
61
- "changelog_1_0_21_tamanami_route": "玉波改二専用の改修素材ルートを追加し、通常ルートと混在しないようにしました。"
61
+ "changelog_1_0_21_tamanami_route": "玉波改二専用の改修素材ルートを追加し、通常ルートと混在しないようにしました。",
62
+ "changelog_1_0_27_data_safety": "不完全または互換性のない改修情報を誤って表示しないよう、データ確認を強化しました。"
62
63
  }
package/i18n/zh-CN.json CHANGED
@@ -58,5 +58,6 @@
58
58
  "changelog_1_0_22_reopen_notes": "工具栏新增“更新日志”按钮,可随时回看版本变化。",
59
59
  "changelog_1_0_21_stable_data": "改修信息的加载和更新更加稳定。",
60
60
  "changelog_1_0_21_separate_routes": "材料、资材或升级目标不同的改修路线现在会分表展示。",
61
- "changelog_1_0_21_tamanami_route": "补充玉波改二专属的改修材料路线,避免与普通路线混在一起。"
61
+ "changelog_1_0_21_tamanami_route": "补充玉波改二专属的改修材料路线,避免与普通路线混在一起。",
62
+ "changelog_1_0_27_data_safety": "加强改修资料完整性检查,遇到不完整或不兼容的资料时会拒绝加载,避免显示错误内容。"
62
63
  }
package/i18n/zh-TW.json CHANGED
@@ -58,5 +58,6 @@
58
58
  "changelog_1_0_22_reopen_notes": "工具列新增「更新日誌」按鈕,可隨時回看版本變更。",
59
59
  "changelog_1_0_21_stable_data": "改修資訊的載入與更新更加穩定。",
60
60
  "changelog_1_0_21_separate_routes": "材料、資材或升級目標不同的改修路線現在會分表顯示。",
61
- "changelog_1_0_21_tamanami_route": "補充玉波改二專屬的改修材料路線,避免與一般路線混在一起。"
61
+ "changelog_1_0_21_tamanami_route": "補充玉波改二專屬的改修材料路線,避免與一般路線混在一起。",
62
+ "changelog_1_0_27_data_safety": "加強改修資料完整性檢查,遇到不完整或不相容的資料時會拒絕載入,避免顯示錯誤內容。"
62
63
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "poi-plugin-item-improvement2-beta",
3
- "version": "1.0.26",
4
- "description": "use new data source",
3
+ "version": "1.0.28",
4
+ "description": "View KanColle equipment improvement schedules, routes, costs, and required materials in Poi",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "prepack": "poi-util-transpile",
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "dom-to-image": "^2.6.0",
36
36
  "react-numeric-input": "^2.2.3",
37
- "@sakura2333/kancolle-data": "^0.1.0"
37
+ "@sakura2333/kancolle-data": ">=0.1.0 <0.3.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "babel-eslint": "^10.0.1",
@@ -63,10 +63,6 @@
63
63
  "views/**/*.js",
64
64
  "assets/**/*",
65
65
  "i18n/*.json",
66
- "scripts/publish-beta.js",
67
- "tests/improvement-data.test.js",
68
- "CHANGELOG.md",
69
- "README.md",
70
- "REFACTOR_NOTES.md"
66
+ "README.md"
71
67
  ]
72
68
  }
@@ -13,6 +13,9 @@ const CHANGELOG_BASELINE_VERSION = '1.0.20'; // Keep in-app notes focused on use
13
13
 
14
14
  exports.CHANGELOG_BASELINE_VERSION = CHANGELOG_BASELINE_VERSION;
15
15
  const CHANGELOG = [{
16
+ version: '1.0.27',
17
+ items: ['changelog_1_0_27_data_safety']
18
+ }, {
16
19
  version: '1.0.26',
17
20
  items: ['changelog_1_0_26_useitem_icon']
18
21
  }, {
@@ -1,14 +1,15 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
- exports.MAX_SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = exports.DATA_PACKAGE_NAME = exports.getUseitemIconPath = exports.getImprovementDataPaths = exports.getDataPackageManifest = void 0;
4
+ exports.validateSchemaVersion = exports.SUPPORTED_IMPROVEMENT_LIST_SCHEMA_VERSION = exports.SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = exports.DATA_PACKAGE_NAME = exports.getUseitemIconPath = exports.getImprovementDataPaths = exports.getDataPackageManifest = void 0;
5
5
 
6
6
  var _fs = _interopRequireDefault(require("fs"));
7
7
 
8
8
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
9
9
 
10
10
  const PACKAGE_NAME = '@sakura2333/kancolle-data';
11
- const SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = 3;
11
+ const IMPROVEMENT_SCHEMA_VERSION = 3;
12
+ const IMPROVEMENT_LIST_SCHEMA_VERSION = 2;
12
13
  let dataPackage = null;
13
14
  let manifest = null;
14
15
 
@@ -26,6 +27,14 @@ function loadDataPackage() {
26
27
  return dataPackage;
27
28
  }
28
29
 
30
+ function requireExactSchema(value, expected, label) {
31
+ const schemaVersion = Number(value);
32
+
33
+ if (!Number.isInteger(schemaVersion) || schemaVersion !== expected) {
34
+ throw new Error(`Unsupported ${label} schema ${value}; supported version is ${expected}`);
35
+ }
36
+ }
37
+
29
38
  function readManifest() {
30
39
  if (manifest) return manifest;
31
40
  const pkg = loadDataPackage();
@@ -41,8 +50,10 @@ function readManifest() {
41
50
  throw new Error(`${PACKAGE_NAME} does not contain the improvement dataset`);
42
51
  }
43
52
 
44
- if (Number(improvement.schemaVersion) > SUPPORTED_IMPROVEMENT_SCHEMA_VERSION) {
45
- throw new Error(`Unsupported improvement schema ${improvement.schemaVersion}; ` + `maximum supported is ${SUPPORTED_IMPROVEMENT_SCHEMA_VERSION}`);
53
+ requireExactSchema(improvement.schemaVersion, IMPROVEMENT_SCHEMA_VERSION, 'improvement detail');
54
+
55
+ if (improvement.listSchemaVersion != null) {
56
+ requireExactSchema(improvement.listSchemaVersion, IMPROVEMENT_LIST_SCHEMA_VERSION, 'improvement list');
46
57
  }
47
58
 
48
59
  return manifest;
@@ -60,6 +71,10 @@ const getImprovementDataPaths = () => {
60
71
  throw new Error(`${PACKAGE_NAME} improvement paths are incomplete`);
61
72
  }
62
73
 
74
+ if (!_fs.default.existsSync(pkg.improvement.listPath) || !_fs.default.existsSync(pkg.improvement.detailPath)) {
75
+ throw new Error(`${PACKAGE_NAME} improvement files are missing`);
76
+ }
77
+
63
78
  return {
64
79
  listPath: pkg.improvement.listPath,
65
80
  detailPath: pkg.improvement.detailPath
@@ -76,5 +91,9 @@ const getUseitemIconPath = id => {
76
91
  exports.getUseitemIconPath = getUseitemIconPath;
77
92
  const DATA_PACKAGE_NAME = PACKAGE_NAME;
78
93
  exports.DATA_PACKAGE_NAME = DATA_PACKAGE_NAME;
79
- const MAX_SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = SUPPORTED_IMPROVEMENT_SCHEMA_VERSION;
80
- exports.MAX_SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = MAX_SUPPORTED_IMPROVEMENT_SCHEMA_VERSION;
94
+ const SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = IMPROVEMENT_SCHEMA_VERSION;
95
+ exports.SUPPORTED_IMPROVEMENT_SCHEMA_VERSION = SUPPORTED_IMPROVEMENT_SCHEMA_VERSION;
96
+ const SUPPORTED_IMPROVEMENT_LIST_SCHEMA_VERSION = IMPROVEMENT_LIST_SCHEMA_VERSION;
97
+ exports.SUPPORTED_IMPROVEMENT_LIST_SCHEMA_VERSION = SUPPORTED_IMPROVEMENT_LIST_SCHEMA_VERSION;
98
+ const validateSchemaVersion = requireExactSchema;
99
+ exports.validateSchemaVersion = validateSchemaVersion;
@@ -26,6 +26,10 @@ function validateListData(data) {
26
26
  throw new Error('Invalid improvement list data');
27
27
  }
28
28
 
29
+ if (Number(data.metadata.schemaVersion) !== 2 || !Array.isArray(data.metadata.rowSchema) || data.metadata.rowSchema.length !== 2 || data.metadata.rowSchema[0] !== 'itemId' || data.metadata.rowSchema[1] !== 'assistantTexts') {
30
+ throw new Error('Unsupported improvement list schema');
31
+ }
32
+
29
33
  data.data.forEach((rows, viewIndex) => {
30
34
  if (!Array.isArray(rows)) {
31
35
  throw new Error(`Invalid improvement list view: ${viewIndex}`);
package/CHANGELOG.md DELETED
@@ -1,107 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to `poi-plugin-item-improvement2-beta` are documented here.
4
-
5
- ## [Unreleased]
6
-
7
- ### Planned
8
-
9
- - Add consumer views for equipment acquisition sources and special ship bonuses from `@sakura2333/kancolle-data`.
10
- - Remove the remaining local compatibility icon after the shared data package contains it.
11
-
12
- ## [1.0.26] - 2026-06-28
13
-
14
- ### Fixed
15
-
16
- - Ensured the local use-item 71 compatibility PNG is explicitly included in official and beta npm packages.
17
- - Re-encoded the unchanged icon pixels so Git patches and repository updates physically carry the binary asset instead of relying on an existing working-tree copy.
18
-
19
- ### Changed
20
-
21
- - Added an explicit npm `files` allowlist covering runtime JavaScript, localized resources, styles, and all icon assets.
22
-
23
- ### Validation
24
-
25
- - Added a package dry-run assertion that fails when `assets/icon/71.png` is absent from the npm tarball file list.
26
- - Added PNG signature validation for the compatibility icon.
27
-
28
- ## [1.0.25] - 2026-06-28
29
-
30
- ### Changed
31
-
32
- - Rewrote the in-app release notes to describe user-visible behavior instead of npm, schema, repository, and packaging implementation details.
33
- - Added localized user-facing release-note copy for Simplified Chinese, Traditional Chinese, Japanese, and English.
34
- - Kept detailed engineering changes in this repository `CHANGELOG.md` for development and release auditing.
35
-
36
- ### Validation
37
-
38
- - Added coverage that every in-app changelog key exists in all supported locales.
39
- - Added coverage preventing technical package terminology from leaking back into the Simplified Chinese in-app release notes.
40
-
41
- ## [1.0.24] - 2026-06-28
42
-
43
- ### Changed
44
-
45
- - Relaxed the shared data dependency from exact `0.1.0` to the compatible `^0.1.0` range.
46
- - New plugin installs and dependency refreshes can now consume automatically published `0.1.x` data-only patch releases without requiring a plugin release for every dataset refresh.
47
-
48
- ### Compatibility
49
-
50
- - Data package minor/schema releases remain blocked until the plugin explicitly updates its supported dependency range and schema checks.
51
- - Existing installed plugins still need their dependency installation to be refreshed before npm can resolve a newer data patch.
52
-
53
- ## [1.0.23] - 2026-06-28
54
-
55
- ### Added
56
-
57
- - Added the versioned `@sakura2333/kancolle-data@0.1.0` runtime dependency.
58
- - Added a data-package adapter that exposes improvement list/detail paths and validates the supported improvement schema.
59
- - Added shared use-item icon lookup through the data package.
60
-
61
- ### Changed
62
-
63
- - Moved improvement list data, improvement detail data, and most use-item PNG assets out of the plugin package.
64
- - Removed runtime GitHub data synchronization; all required data is installed locally by npm.
65
- - Changed official and beta builds to consume the same versioned data package.
66
- - Reduced the plugin tarball from the historical embedded-data size to a lightweight code package.
67
- - Kept the local `71.png` and generic SVG as temporary compatibility assets.
68
-
69
- ### Fixed
70
-
71
- - Fixed plugin startup being dependent on GitHub Raw availability and network conditions.
72
- - Fixed data and PNG updates requiring duplicate copies in the Spider and plugin repositories.
73
-
74
- ### Compatibility
75
-
76
- - Requires `@sakura2333/kancolle-data` with a supported improvement schema.
77
- - Publish the data package before publishing a plugin version that depends on it.
78
-
79
- ## [1.0.22] - 2026-06-28
80
-
81
- ### Added
82
-
83
- - Added a localized release-notes dialog shown once after a version change.
84
- - Added a toolbar entry for reopening the release notes manually.
85
- - Added `publish:beta` and `publish:beta:dry-run` scripts.
86
-
87
- ### Changed
88
-
89
- - Beta publishing temporarily changes package and runtime namespaces to `poi-plugin-item-improvement2-beta-beta` and always restores the working tree afterward.
90
-
91
- ## [1.0.21] - 2026-06-28
92
-
93
- ### Added
94
-
95
- - Added separate list and detail data projections.
96
- - Added support for multiple independent improvement recipe routes.
97
- - Added the Tamanami Kai Ni assistant-specific material route.
98
-
99
- ### Changed
100
-
101
- - Changed the detail UI to render one table per complete recipe route.
102
- - Unified list and detail assistant presentation through normalized view models.
103
-
104
- ### Fixed
105
-
106
- - Fixed routes with different materials, costs, or upgrade targets sharing the first route's table header.
107
- - Fixed the default route and Tamanami Kai Ni route being merged back together in the UI.
package/REFACTOR_NOTES.md DELETED
@@ -1,43 +0,0 @@
1
- # Data package and route-aware UI
2
-
3
- ## Runtime data
4
-
5
- The plugin consumes the versioned npm dependency `@sakura2333/kancolle-data`:
6
-
7
- - `improvement/list.json`: compact all + seven-day list projection.
8
- - `improvement/detail.nedb`: full equipment detail and recipe routes.
9
- - `assets/useitems/*.png`: shared use-item icons.
10
-
11
- The plugin no longer downloads GitHub files at runtime and no longer carries duplicate
12
- improvement datasets. `assets/icon/useitem.svg` remains the generic fallback; the legacy
13
- `71.png` is temporarily retained until it is present in the data package.
14
-
15
- ## Responsibility boundary
16
-
17
- - Spider collects and validates sources, normalizes assistant IDs, splits concrete recipes,
18
- and publishes `@sakura2333/kancolle-data`.
19
- - The data package exposes stable local paths and dataset manifests.
20
- - The plugin reads the installed package, validates the supported improvement schema, and
21
- maps the data into UI view models.
22
- - The list page reads backend-provided `[itemId, assistantTexts]` rows.
23
- - The detail page displays every `improvementList[]` entry as one independent route.
24
-
25
- ## Multiple route support
26
-
27
- `DetailRow` renders one table per improvement route. Each table uses its own base resources,
28
- stage costs, consumables, MAX target, and assistant schedule. This supports assistant-specific
29
- recipes such as the `玉波改二` route for `12.7cm連装砲D型改二`.
30
-
31
- ## Publish order
32
-
33
- 1. Build and publish `@sakura2333/kancolle-data` from the Spider repository.
34
- 2. Install development dependencies for this plugin.
35
- 3. Run tests and publish the official or beta plugin.
36
-
37
- ```bash
38
- npm ci --include=dev
39
- npm test
40
- npm publish
41
- # or
42
- npm run publish:beta
43
- ```
@@ -1,163 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- 'use strict'
4
-
5
- const fs = require('fs')
6
- const path = require('path')
7
- const { spawn } = require('child_process')
8
-
9
- const ROOT = path.resolve(__dirname, '..')
10
- const OFFICIAL_NAME = 'poi-plugin-item-improvement2'
11
- const BETA_NAME = 'poi-plugin-item-improvement2-beta'
12
- const SELF_PATH = path.resolve(__filename)
13
- const SKIP_DIRECTORIES = new Set(['.git', 'node_modules'])
14
- const MAX_TEXT_FILE_SIZE = 5 * 1024 * 1024
15
-
16
- function isProbablyText(buffer) {
17
- return !buffer.includes(0)
18
- }
19
-
20
- function collectFiles(directory, output = []) {
21
- for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
22
- if (entry.isDirectory() && SKIP_DIRECTORIES.has(entry.name)) continue
23
-
24
- const absolutePath = path.join(directory, entry.name)
25
- if (entry.isDirectory()) {
26
- collectFiles(absolutePath, output)
27
- } else if (entry.isFile()) {
28
- output.push(absolutePath)
29
- }
30
- }
31
- return output
32
- }
33
-
34
- function buildReplacementPlan() {
35
- const replacements = []
36
-
37
- for (const filePath of collectFiles(ROOT)) {
38
- if (path.resolve(filePath) === SELF_PATH) continue
39
-
40
- const stat = fs.statSync(filePath)
41
- if (stat.size > MAX_TEXT_FILE_SIZE) continue
42
-
43
- const original = fs.readFileSync(filePath)
44
- if (!isProbablyText(original)) continue
45
-
46
- const originalText = original.toString('utf8')
47
- if (!originalText.includes(OFFICIAL_NAME)) continue
48
-
49
- const betaText = originalText.split(OFFICIAL_NAME).join(BETA_NAME)
50
- replacements.push({
51
- filePath,
52
- original,
53
- replacement: Buffer.from(betaText, 'utf8'),
54
- })
55
- }
56
-
57
- return replacements
58
- }
59
-
60
- function assertOfficialWorkspace() {
61
- const packageJsonPath = path.join(ROOT, 'package.json')
62
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
63
-
64
- if (packageJson.name !== OFFICIAL_NAME) {
65
- throw new Error(
66
- `Expected package.json name to be ${OFFICIAL_NAME}, got ${packageJson.name}`
67
- )
68
- }
69
- }
70
-
71
- function applyReplacementPlan(plan) {
72
- for (const entry of plan) {
73
- fs.writeFileSync(entry.filePath, entry.replacement)
74
- }
75
- }
76
-
77
- function restoreReplacementPlan(plan) {
78
- for (const entry of plan) {
79
- fs.writeFileSync(entry.filePath, entry.original)
80
- }
81
- }
82
-
83
- function relative(filePath) {
84
- return path.relative(ROOT, filePath) || '.'
85
- }
86
-
87
- function runNpmPublish(args) {
88
- const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'
89
-
90
- return new Promise((resolve, reject) => {
91
- const child = spawn(npmCommand, ['publish', ...args], {
92
- cwd: ROOT,
93
- env: process.env,
94
- stdio: 'inherit',
95
- })
96
-
97
- const forwardSignal = signal => {
98
- if (!child.killed) child.kill(signal)
99
- }
100
-
101
- process.once('SIGINT', forwardSignal)
102
- process.once('SIGTERM', forwardSignal)
103
-
104
- child.once('error', error => {
105
- process.removeListener('SIGINT', forwardSignal)
106
- process.removeListener('SIGTERM', forwardSignal)
107
- reject(error)
108
- })
109
-
110
- child.once('exit', (code, signal) => {
111
- process.removeListener('SIGINT', forwardSignal)
112
- process.removeListener('SIGTERM', forwardSignal)
113
-
114
- if (signal) {
115
- reject(new Error(`npm publish terminated by ${signal}`))
116
- } else {
117
- resolve(code == null ? 1 : code)
118
- }
119
- })
120
- })
121
- }
122
-
123
- async function main() {
124
- assertOfficialWorkspace()
125
-
126
- const plan = buildReplacementPlan()
127
- if (plan.length === 0) {
128
- throw new Error(`No occurrences of ${OFFICIAL_NAME} were found`)
129
- }
130
-
131
- console.log(`Temporarily switching package namespace:`)
132
- console.log(` ${OFFICIAL_NAME} -> ${BETA_NAME}`)
133
- console.log('Changed files:')
134
- for (const entry of plan) {
135
- console.log(` - ${relative(entry.filePath)}`)
136
- }
137
-
138
- let exitCode = 1
139
- applyReplacementPlan(plan)
140
-
141
- try {
142
- const betaPackage = JSON.parse(
143
- fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')
144
- )
145
- if (betaPackage.name !== BETA_NAME) {
146
- throw new Error('Temporary beta package-name replacement failed')
147
- }
148
-
149
- exitCode = await runNpmPublish(process.argv.slice(2))
150
- } finally {
151
- restoreReplacementPlan(plan)
152
- console.log(`Restored workspace namespace to ${OFFICIAL_NAME}`)
153
- }
154
-
155
- if (exitCode !== 0) {
156
- throw new Error(`npm publish exited with code ${exitCode}`)
157
- }
158
- }
159
-
160
- main().catch(error => {
161
- console.error(`[publish:beta] ${error.message}`)
162
- process.exitCode = 1
163
- })
@@ -1,271 +0,0 @@
1
- const assert = require('assert')
2
- const fs = require('fs')
3
- const path = require('path')
4
- const { execFileSync } = require('child_process')
5
- const {
6
- buildAssistantTextByDay,
7
- buildImprovementItem,
8
- createShipNameResolver,
9
- normalizeAssistant,
10
- normalizeListProjection,
11
- normalizeShipIds,
12
- } = require('../views/improvement-data.js')
13
-
14
-
15
- const {
16
- CHANGELOG,
17
- compareVersions,
18
- getChangelogEntriesSince,
19
- } = require('../views/changelog.js')
20
-
21
- assert.strictEqual(compareVersions('1.0.22', '1.0.21'), 1)
22
- assert.strictEqual(compareVersions('1.0.21', '1.0.21'), 0)
23
- assert.strictEqual(compareVersions('1.0.20', '1.0.21'), -1)
24
- assert.deepStrictEqual(
25
- getChangelogEntriesSince('1.0.21').map(entry => entry.version),
26
- ['1.0.26', '1.0.25', '1.0.24', '1.0.23', '1.0.22']
27
- )
28
- assert.deepStrictEqual(
29
- getChangelogEntriesSince(null).map(entry => entry.version),
30
- ['1.0.26', '1.0.25', '1.0.24', '1.0.23', '1.0.22', '1.0.21']
31
- )
32
-
33
- const localeNames = ['zh-CN', 'zh-TW', 'ja-JP', 'en-US']
34
- const locales = localeNames.reduce((result, localeName) => {
35
- const localePath = path.join(__dirname, '..', 'i18n', `${localeName}.json`)
36
- result[localeName] = JSON.parse(fs.readFileSync(localePath, 'utf8'))
37
- return result
38
- }, {})
39
-
40
- const changelogKeys = CHANGELOG.reduce(
41
- (keys, entry) => keys.concat(entry.items),
42
- []
43
- )
44
-
45
- localeNames.forEach(localeName => {
46
- changelogKeys.forEach(key => {
47
- assert.strictEqual(
48
- typeof locales[localeName][key],
49
- 'string',
50
- `${localeName} is missing changelog entry ${key}`
51
- )
52
- assert.ok(
53
- locales[localeName][key].trim().length > 0,
54
- `${localeName} has an empty changelog entry ${key}`
55
- )
56
- })
57
- })
58
-
59
- const technicalTerms = [
60
- '@sakura2333/kancolle-data',
61
- 'npm',
62
- 'Schema',
63
- '0.1.x',
64
- 'PNG',
65
- 'GitHub',
66
- ]
67
- const simplifiedChineseNotes = changelogKeys
68
- .map(key => locales['zh-CN'][key])
69
- .join('\n')
70
- technicalTerms.forEach(term => {
71
- assert.strictEqual(
72
- simplifiedChineseNotes.includes(term),
73
- false,
74
- `user-facing changelog should not contain technical term: ${term}`
75
- )
76
- })
77
-
78
- const projectRoot = path.join(__dirname, '..')
79
- const compatibilityIconPath = path.join(projectRoot, 'assets', 'icon', '71.png')
80
- const pngSignature = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])
81
- assert.ok(fs.existsSync(compatibilityIconPath), 'compatibility icon 71.png is missing')
82
- assert.ok(
83
- fs.readFileSync(compatibilityIconPath).subarray(0, 8).equals(pngSignature),
84
- 'compatibility icon 71.png is not a valid PNG'
85
- )
86
-
87
- const dryRunOutput = execFileSync(
88
- process.platform === 'win32' ? 'npm.cmd' : 'npm',
89
- ['pack', '--dry-run', '--json', '--ignore-scripts'],
90
- { cwd: projectRoot, encoding: 'utf8' }
91
- )
92
- const dryRun = JSON.parse(dryRunOutput)
93
- const packedFiles = new Set(dryRun[0].files.map(file => file.path))
94
- assert.ok(
95
- packedFiles.has('assets/icon/71.png'),
96
- 'npm package is missing assets/icon/71.png'
97
- )
98
-
99
-
100
- const ships = {
101
- 89: { api_id: 89, api_name: '鳳翔' },
102
- 622: { api_id: 622, api_name: '夕張改二' },
103
- 623: { api_id: 623, api_name: '夕張改二特' },
104
- 624: { api_id: 624, api_name: '夕張改二丁' },
105
- 718: { api_id: 718, api_name: '玉波改' },
106
- 1033: { api_id: 1033, api_name: '玉波改二' },
107
- }
108
-
109
- const resolveShipName = createShipNameResolver(ships, name => `local:${name}`)
110
-
111
- const exact = normalizeAssistant({
112
- id: [89],
113
- text: '鳳翔',
114
- week: [true, false, false, false, false, false, false],
115
- }, resolveShipName)
116
- assert.deepStrictEqual(exact.shipIds, [89])
117
- assert.strictEqual(exact.idsComplete, true)
118
- assert.strictEqual(exact.displayText, 'local:鳳翔')
119
-
120
- const legacyIrregular = normalizeAssistant({
121
- id: [622],
122
- text: '夕張改二/特/丁',
123
- week: [true, true, true, true, true, true, true],
124
- }, resolveShipName)
125
- assert.strictEqual(legacyIrregular.idsComplete, false)
126
- assert.strictEqual(legacyIrregular.displayText, '夕張改二/特/丁')
127
-
128
- const generatedButNotConnected = normalizeAssistant({
129
- id: [622],
130
- shipIdList: [622, 623, 624],
131
- text: '夕張改二/特/丁',
132
- parseStatus: 'resolved',
133
- week: [true, true, true, true, true, true, true],
134
- }, resolveShipName)
135
- assert.strictEqual(generatedButNotConnected.idsComplete, false)
136
- assert.strictEqual(generatedButNotConnected.displayText, '夕張改二/特/丁')
137
-
138
- const resolvedMultiple = normalizeAssistant({
139
- id: [622, 623, 624],
140
- text: '夕張改二/特/丁',
141
- week: [true, true, true, true, true, true, true],
142
- }, resolveShipName)
143
- assert.strictEqual(resolvedMultiple.idsComplete, true)
144
- assert.strictEqual(
145
- resolvedMultiple.displayText,
146
- 'local:夕張改二 / local:夕張改二特 / local:夕張改二丁'
147
- )
148
-
149
- const explicitSingle = normalizeAssistant({
150
- id: [622],
151
- text: '夕張改二のみ',
152
- idsComplete: true,
153
- week: [true, true, true, true, true, true, true],
154
- }, resolveShipName)
155
- assert.strictEqual(explicitSingle.displayText, 'local:夕張改二')
156
-
157
- const unknown = normalizeAssistant({
158
- shipIds: [9999],
159
- resolved: true,
160
- week: [true],
161
- }, resolveShipName)
162
- assert.strictEqual(unknown.displayText, '#9999')
163
-
164
- assert.deepStrictEqual(normalizeShipIds({ id: ['89', 89, 0, 'bad'] }), [89])
165
-
166
-
167
- const noSpecificAssistant = normalizeAssistant({
168
- id: [0],
169
- text: '',
170
- week: [true, true, false, false, false, false, false],
171
- }, resolveShipName)
172
- assert.deepStrictEqual(noSpecificAssistant.shipIds, [])
173
- assert.strictEqual(noSpecificAssistant.displayText, '')
174
- assert.deepStrictEqual(noSpecificAssistant.days, [0, 1])
175
-
176
- const improvementList = [
177
- {
178
- assistantList: [exact, legacyIrregular],
179
- },
180
- ]
181
- const textByDay = buildAssistantTextByDay(improvementList)
182
- assert.strictEqual(textByDay[0], 'local:鳳翔 / 夕張改二/特/丁')
183
- assert.strictEqual(textByDay[1], '夕張改二/特/丁')
184
- assert.strictEqual(textByDay[-1], 'local:鳳翔 / 夕張改二/特/丁')
185
-
186
- const item = buildImprovementItem({
187
- id: 19,
188
- improvementList: [
189
- {
190
- shipWeekList: [
191
- {
192
- id: [89],
193
- text: '鳳翔',
194
- week: [true, false, false, false, false, false, false],
195
- },
196
- ],
197
- },
198
- ],
199
- }, { api_name: '九六式艦戦' }, resolveShipName)
200
- assert.strictEqual(item.api_name, '九六式艦戦')
201
- assert.strictEqual(item.improvementList[0].assistantList[0].displayText, 'local:鳳翔')
202
- assert.strictEqual(item.assistantTextByDay[0], 'local:鳳翔')
203
- assert.strictEqual(item.assistantTextByDay[1], '')
204
-
205
-
206
- const listProjection = normalizeListProjection({
207
- metadata: { schemaVersion: 2 },
208
- data: [
209
- [[19, ['鳳翔', '鳳翔改二']]],
210
- [[19, ['鳳翔']]],
211
- [], [], [], [], [], [],
212
- ],
213
- })
214
- assert.deepStrictEqual(listProjection.itemIdsByDay[-1], [19])
215
- assert.deepStrictEqual(listProjection.itemIdsByDay[0], [19])
216
- assert.strictEqual(listProjection.assistantTextByItemId[19][-1], '鳳翔 / 鳳翔改二')
217
- assert.strictEqual(listProjection.assistantTextByItemId[19][0], '鳳翔')
218
-
219
- const kancolleData = require('@sakura2333/kancolle-data')
220
-
221
- const {
222
- DATA_PACKAGE_NAME,
223
- MAX_SUPPORTED_IMPROVEMENT_SCHEMA_VERSION,
224
- getDataPackageManifest,
225
- getImprovementDataPaths,
226
- getUseitemIconPath,
227
- } = require('../views/data-package.js')
228
-
229
- const packageManifest = getDataPackageManifest()
230
- assert.strictEqual(DATA_PACKAGE_NAME, '@sakura2333/kancolle-data')
231
- assert.strictEqual(packageManifest.datasets.improvement.schemaVersion, 3)
232
- assert.strictEqual(MAX_SUPPORTED_IMPROVEMENT_SCHEMA_VERSION, 3)
233
- assert.ok(fs.existsSync(getImprovementDataPaths().listPath))
234
- assert.ok(fs.existsSync(getImprovementDataPaths().detailPath))
235
- assert.ok(fs.existsSync(getUseitemIconPath(57)))
236
- const listAsset = JSON.parse(fs.readFileSync(kancolleData.improvement.listPath, 'utf8'))
237
- const detailIds = new Set(
238
- fs.readFileSync(kancolleData.improvement.detailPath, 'utf8')
239
- .split('\n')
240
- .filter(Boolean)
241
- .map(line => JSON.parse(line).id)
242
- )
243
- assert.strictEqual(listAsset.metadata.schemaVersion, 2)
244
- assert.ok(fs.existsSync(kancolleData.manifestPath))
245
- assert.ok(fs.existsSync(kancolleData.assets.useitemPath(57)))
246
- assert.strictEqual(listAsset.data.length, 8)
247
- listAsset.data.forEach(rows => rows.forEach(([itemId]) => assert.ok(detailIds.has(itemId))))
248
-
249
-
250
- const detailRows = fs.readFileSync(kancolleData.improvement.detailPath, 'utf8')
251
- .split('\n')
252
- .filter(Boolean)
253
- .map(line => JSON.parse(line))
254
- const tamanamiRouteItem = detailRows.find(row => row.id === 267)
255
- assert.ok(tamanamiRouteItem)
256
- assert.strictEqual(tamanamiRouteItem.improvementList.length, 2)
257
- const normalRoute = tamanamiRouteItem.improvementList.find(route => route.routeType === 'default')
258
- const specialRoute = tamanamiRouteItem.improvementList.find(route => route.routeType === 'assistant-specific')
259
- assert.ok(normalRoute)
260
- assert.ok(specialRoute)
261
- assert.deepStrictEqual(specialRoute.routeShipIds, [1033])
262
- assert.deepStrictEqual(specialRoute.stageList[0].consumables, [{ id: 10, count: 3, type: 0 }])
263
- assert.deepStrictEqual(normalRoute.stageList[0].consumables, [{ id: 3, count: 2, type: 0 }])
264
- const normalizedTamanami = buildImprovementItem(tamanamiRouteItem, { api_name: tamanamiRouteItem.name }, resolveShipName)
265
- assert.strictEqual(normalizedTamanami.improvementList.length, 2)
266
- assert.strictEqual(
267
- normalizedTamanami.improvementList.find(route => route.routeType === 'assistant-specific').assistantList[0].displayText,
268
- 'local:玉波改二'
269
- )
270
-
271
- console.log('improvement-data tests passed')