@pagepocket/cli 0.10.1 → 0.11.1
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/dist/commands/archive.js +146 -76
- package/dist/commands/plugin/add.js +19 -25
- package/dist/commands/plugin/doctor.js +22 -28
- package/dist/commands/plugin/ls.js +16 -22
- package/dist/commands/plugin/prune.js +13 -19
- package/dist/commands/plugin/remove.js +16 -22
- package/dist/commands/plugin/set.js +13 -19
- package/dist/commands/plugin/uninstall.js +29 -35
- package/dist/commands/plugin/update.js +22 -28
- package/dist/commands/strategy/add.js +14 -20
- package/dist/commands/strategy/doctor.js +11 -17
- package/dist/commands/strategy/ls.js +22 -0
- package/dist/commands/strategy/pin.js +10 -16
- package/dist/commands/strategy/remove.js +10 -16
- package/dist/commands/strategy/update.js +21 -27
- package/dist/commands/view.js +36 -42
- package/dist/index.js +9 -7
- package/dist/lib/filename.js +1 -5
- package/dist/services/config-service.js +24 -30
- package/dist/services/load-configured-plugins.js +8 -12
- package/dist/services/plugin-installer.js +6 -12
- package/dist/services/plugin-store.js +27 -68
- package/dist/services/strategy/builtin-strategy-registry.js +23 -0
- package/dist/services/strategy/strategy-analyze.js +10 -20
- package/dist/services/strategy/strategy-config.js +6 -13
- package/dist/services/strategy/strategy-fetch.js +11 -18
- package/dist/services/strategy/strategy-io.js +15 -25
- package/dist/services/strategy/strategy-normalize.js +4 -8
- package/dist/services/strategy/strategy-pack-read.js +10 -17
- package/dist/services/strategy/strategy-pack-store.js +12 -18
- package/dist/services/strategy/strategy-service.js +79 -82
- package/dist/services/strategy/types.js +1 -2
- package/dist/services/units/unit-store.js +16 -20
- package/dist/services/units/unit-validate.js +20 -5
- package/dist/services/user-packages/parse-pinned-spec.js +6 -6
- package/dist/services/user-packages/user-package-installer.js +4 -9
- package/dist/services/user-packages/user-package-store.js +19 -57
- package/dist/stages/prepare-output.js +6 -13
- package/dist/units/network-observer-unit.js +7 -10
- package/dist/utils/array.js +3 -0
- package/dist/utils/normalize-argv.js +3 -8
- package/dist/utils/parse-json.js +1 -5
- package/dist/utils/parse-plugin-options.js +1 -5
- package/dist/utils/parse-plugin-spec.js +6 -6
- package/dist/utils/validate-plugin-default-export.js +1 -5
- package/dist/utils/with-spinner.js +3 -10
- package/dist/view.js +12 -19
- package/package.json +12 -11
- package/dist/services/strategy/read-installed-package-version.js +0 -28
|
@@ -1,55 +1,50 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
exports.ConfigService = void 0;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
-
const env_paths_1 = __importDefault(require("env-paths"));
|
|
11
|
-
const parse_json_1 = require("../utils/parse-json");
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import envPaths from "env-paths";
|
|
5
|
+
import { parseJson } from "../utils/parse-json.js";
|
|
12
6
|
const defaultConfig = {
|
|
13
7
|
plugins: [],
|
|
14
8
|
strategies: [],
|
|
15
9
|
strategyPacks: []
|
|
16
10
|
};
|
|
17
|
-
class ConfigService {
|
|
11
|
+
export class ConfigService {
|
|
12
|
+
appName;
|
|
18
13
|
constructor(appName = "pagepocket") {
|
|
19
14
|
this.appName = appName;
|
|
20
15
|
}
|
|
21
16
|
getConfigDir() {
|
|
22
17
|
if (process.platform === "win32") {
|
|
23
|
-
const p = (
|
|
18
|
+
const p = envPaths(this.appName, { suffix: "" });
|
|
24
19
|
return p.config;
|
|
25
20
|
}
|
|
26
|
-
const homeDir =
|
|
21
|
+
const homeDir = os.homedir();
|
|
27
22
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
28
|
-
const base = xdgConfigHome && xdgConfigHome.trim() ? xdgConfigHome :
|
|
29
|
-
return
|
|
23
|
+
const base = xdgConfigHome && xdgConfigHome.trim() ? xdgConfigHome : path.join(homeDir, ".config");
|
|
24
|
+
return path.join(base, this.appName);
|
|
30
25
|
}
|
|
31
26
|
getDataDir() {
|
|
32
|
-
const p = (
|
|
27
|
+
const p = envPaths(this.appName, { suffix: "" });
|
|
33
28
|
return p.data;
|
|
34
29
|
}
|
|
35
30
|
getConfigPath() {
|
|
36
|
-
return
|
|
31
|
+
return path.join(this.getConfigDir(), "config.json");
|
|
37
32
|
}
|
|
38
33
|
getPluginsInstallDir() {
|
|
39
|
-
return
|
|
34
|
+
return path.join(this.getDataDir(), "plugins");
|
|
40
35
|
}
|
|
41
36
|
ensureConfigDirExists() {
|
|
42
37
|
this.ensureDirExists(this.getConfigDir());
|
|
43
38
|
}
|
|
44
39
|
ensureDirExists(dirPath) {
|
|
45
|
-
|
|
40
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
46
41
|
}
|
|
47
42
|
writeJsonAtomic(filePath, value) {
|
|
48
|
-
const dir =
|
|
43
|
+
const dir = path.dirname(filePath);
|
|
49
44
|
this.ensureDirExists(dir);
|
|
50
45
|
const tmpPath = `${filePath}.tmp`;
|
|
51
|
-
|
|
52
|
-
|
|
46
|
+
fs.writeFileSync(tmpPath, `${JSON.stringify(value, undefined, 2)}\n`, "utf8");
|
|
47
|
+
fs.renameSync(tmpPath, filePath);
|
|
53
48
|
}
|
|
54
49
|
isObject(value) {
|
|
55
50
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
@@ -113,20 +108,20 @@ class ConfigService {
|
|
|
113
108
|
}
|
|
114
109
|
readConfig() {
|
|
115
110
|
const configPath = this.getConfigPath();
|
|
116
|
-
const rawText =
|
|
117
|
-
const parsed =
|
|
111
|
+
const rawText = fs.readFileSync(configPath, "utf8");
|
|
112
|
+
const parsed = parseJson(rawText);
|
|
118
113
|
return this.normalizeConfig(parsed.ok ? parsed.value : undefined);
|
|
119
114
|
}
|
|
120
115
|
isConfigFilePresent() {
|
|
121
|
-
return
|
|
116
|
+
return fs.existsSync(this.getConfigPath());
|
|
122
117
|
}
|
|
123
118
|
readConfigOrDefault() {
|
|
124
119
|
const configPath = this.getConfigPath();
|
|
125
|
-
const text =
|
|
120
|
+
const text = fs.existsSync(configPath) ? fs.readFileSync(configPath, "utf8") : undefined;
|
|
126
121
|
if (!text) {
|
|
127
122
|
return defaultConfig;
|
|
128
123
|
}
|
|
129
|
-
const parsed =
|
|
124
|
+
const parsed = parseJson(text);
|
|
130
125
|
return parsed.ok ? this.normalizeConfig(parsed.value) : defaultConfig;
|
|
131
126
|
}
|
|
132
127
|
writeConfig(config) {
|
|
@@ -134,11 +129,10 @@ class ConfigService {
|
|
|
134
129
|
}
|
|
135
130
|
ensureConfigFileExists() {
|
|
136
131
|
const configPath = this.getConfigPath();
|
|
137
|
-
if (
|
|
132
|
+
if (fs.existsSync(configPath)) {
|
|
138
133
|
return this.readConfigOrDefault();
|
|
139
134
|
}
|
|
140
135
|
this.writeConfig(defaultConfig);
|
|
141
136
|
return defaultConfig;
|
|
142
137
|
}
|
|
143
138
|
}
|
|
144
|
-
exports.ConfigService = ConfigService;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const config_service_1 = require("./config-service");
|
|
6
|
-
const plugin_store_1 = require("./plugin-store");
|
|
7
|
-
const loadConfiguredPlugins = async () => {
|
|
1
|
+
import { validatePluginDefaultExport } from "../utils/validate-plugin-default-export.js";
|
|
2
|
+
import { ConfigService } from "./config-service.js";
|
|
3
|
+
import { normalizePluginConfigEntry, PluginStore } from "./plugin-store.js";
|
|
4
|
+
export const loadConfiguredPlugins = async () => {
|
|
8
5
|
const getErrorMessage = (error) => {
|
|
9
6
|
if (error instanceof Error) {
|
|
10
7
|
return error.message;
|
|
@@ -17,15 +14,15 @@ const loadConfiguredPlugins = async () => {
|
|
|
17
14
|
}
|
|
18
15
|
return String(error);
|
|
19
16
|
};
|
|
20
|
-
const configService = new
|
|
21
|
-
const store = new
|
|
17
|
+
const configService = new ConfigService();
|
|
18
|
+
const store = new PluginStore(configService);
|
|
22
19
|
configService.ensureConfigFileExists();
|
|
23
20
|
const config = configService.readConfigOrDefault();
|
|
24
|
-
const specs = config.plugins.map(
|
|
21
|
+
const specs = config.plugins.map(normalizePluginConfigEntry);
|
|
25
22
|
const loaded = await Promise.all(specs.map(async (spec) => {
|
|
26
23
|
try {
|
|
27
24
|
const mod = await store.importPluginModule(spec.name);
|
|
28
|
-
const validation =
|
|
25
|
+
const validation = validatePluginDefaultExport({
|
|
29
26
|
pluginName: spec.name,
|
|
30
27
|
moduleExports: mod,
|
|
31
28
|
options: spec.options
|
|
@@ -44,4 +41,3 @@ const loadConfiguredPlugins = async () => {
|
|
|
44
41
|
}));
|
|
45
42
|
return loaded.filter((x) => typeof x !== "undefined");
|
|
46
43
|
};
|
|
47
|
-
exports.loadConfiguredPlugins = loadConfiguredPlugins;
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.uninstallPluginPackage = exports.updatePluginPackageToLatest = exports.installPluginPackage = void 0;
|
|
4
|
-
const node_child_process_1 = require("node:child_process");
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
5
2
|
/**
|
|
6
3
|
* Install a package spec with pnpm first, then fallback to npm.
|
|
7
4
|
*
|
|
@@ -10,7 +7,7 @@ const node_child_process_1 = require("node:child_process");
|
|
|
10
7
|
*/
|
|
11
8
|
const tryInstallWithFallback = (installDir, packageSpec) => {
|
|
12
9
|
const tryRun = (cmd, args) => {
|
|
13
|
-
const r =
|
|
10
|
+
const r = spawnSync(cmd, args, {
|
|
14
11
|
cwd: installDir,
|
|
15
12
|
stdio: "inherit",
|
|
16
13
|
shell: false
|
|
@@ -33,30 +30,28 @@ const tryInstallWithFallback = (installDir, packageSpec) => {
|
|
|
33
30
|
}
|
|
34
31
|
throw new Error(`Failed to install ${packageSpec}. Ensure pnpm or npm is available.`);
|
|
35
32
|
};
|
|
36
|
-
const installPluginPackage = (store, input) => {
|
|
33
|
+
export const installPluginPackage = (store, input) => {
|
|
37
34
|
store.ensurePluginPackageJson();
|
|
38
35
|
const installDir = store.getInstallDir();
|
|
39
36
|
tryInstallWithFallback(installDir, input.packageName);
|
|
40
37
|
};
|
|
41
|
-
|
|
42
|
-
const updatePluginPackageToLatest = (store, input) => {
|
|
38
|
+
export const updatePluginPackageToLatest = (store, input) => {
|
|
43
39
|
store.ensurePluginPackageJson();
|
|
44
40
|
const installDir = store.getInstallDir();
|
|
45
41
|
const packageSpec = `${input.packageName}@latest`;
|
|
46
42
|
tryInstallWithFallback(installDir, packageSpec);
|
|
47
43
|
};
|
|
48
|
-
exports.updatePluginPackageToLatest = updatePluginPackageToLatest;
|
|
49
44
|
/**
|
|
50
45
|
* Uninstall a package name with pnpm first, then fallback to npm.
|
|
51
46
|
*
|
|
52
47
|
* Usage:
|
|
53
48
|
* uninstallPluginPackage(store, { packageName: "@scope/plugin" });
|
|
54
49
|
*/
|
|
55
|
-
const uninstallPluginPackage = (store, input) => {
|
|
50
|
+
export const uninstallPluginPackage = (store, input) => {
|
|
56
51
|
store.ensurePluginPackageJson();
|
|
57
52
|
const installDir = store.getInstallDir();
|
|
58
53
|
const tryRun = (cmd, args) => {
|
|
59
|
-
const r =
|
|
54
|
+
const r = spawnSync(cmd, args, {
|
|
60
55
|
cwd: installDir,
|
|
61
56
|
stdio: "inherit",
|
|
62
57
|
shell: false
|
|
@@ -79,4 +74,3 @@ const uninstallPluginPackage = (store, input) => {
|
|
|
79
74
|
}
|
|
80
75
|
throw new Error(`Failed to uninstall ${input.packageName}. Ensure pnpm or npm is available.`);
|
|
81
76
|
};
|
|
82
|
-
exports.uninstallPluginPackage = uninstallPluginPackage;
|
|
@@ -1,49 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.PluginStore = exports.getPluginNameFromSpec = exports.normalizePluginConfigEntry = void 0;
|
|
40
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
41
|
-
const node_module_1 = require("node:module");
|
|
42
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
43
|
-
const node_url_1 = require("node:url");
|
|
44
|
-
const parse_json_1 = require("../utils/parse-json");
|
|
45
|
-
const validate_plugin_default_export_1 = require("../utils/validate-plugin-default-export");
|
|
46
|
-
const normalizePluginConfigEntry = (entry) => {
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
5
|
+
import { parseJson } from "../utils/parse-json.js";
|
|
6
|
+
import { validatePluginDefaultExport } from "../utils/validate-plugin-default-export.js";
|
|
7
|
+
export const normalizePluginConfigEntry = (entry) => {
|
|
47
8
|
if (typeof entry === "string") {
|
|
48
9
|
return { name: entry };
|
|
49
10
|
}
|
|
@@ -53,9 +14,7 @@ const normalizePluginConfigEntry = (entry) => {
|
|
|
53
14
|
...(typeof entry.options === "undefined" ? {} : { options: entry.options })
|
|
54
15
|
};
|
|
55
16
|
};
|
|
56
|
-
|
|
57
|
-
const getPluginNameFromSpec = (spec) => spec.name;
|
|
58
|
-
exports.getPluginNameFromSpec = getPluginNameFromSpec;
|
|
17
|
+
export const getPluginNameFromSpec = (spec) => spec.name;
|
|
59
18
|
const isRecord = (value) => {
|
|
60
19
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
61
20
|
};
|
|
@@ -68,7 +27,8 @@ const isStringRecord = (value) => {
|
|
|
68
27
|
}
|
|
69
28
|
return Object.values(value).every((v) => typeof v === "string");
|
|
70
29
|
};
|
|
71
|
-
class PluginStore {
|
|
30
|
+
export class PluginStore {
|
|
31
|
+
configService;
|
|
72
32
|
constructor(configService) {
|
|
73
33
|
this.configService = configService;
|
|
74
34
|
}
|
|
@@ -76,12 +36,12 @@ class PluginStore {
|
|
|
76
36
|
return this.configService.getPluginsInstallDir();
|
|
77
37
|
}
|
|
78
38
|
ensureInstallDir() {
|
|
79
|
-
|
|
39
|
+
fs.mkdirSync(this.getInstallDir(), { recursive: true });
|
|
80
40
|
}
|
|
81
41
|
ensurePluginPackageJson() {
|
|
82
42
|
this.ensureInstallDir();
|
|
83
|
-
const pkgJsonPath =
|
|
84
|
-
if (
|
|
43
|
+
const pkgJsonPath = path.join(this.getInstallDir(), "package.json");
|
|
44
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
85
45
|
return pkgJsonPath;
|
|
86
46
|
}
|
|
87
47
|
const pkgJson = {
|
|
@@ -89,20 +49,20 @@ class PluginStore {
|
|
|
89
49
|
private: true,
|
|
90
50
|
version: "0.0.0"
|
|
91
51
|
};
|
|
92
|
-
|
|
52
|
+
fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkgJson, undefined, 2)}\n`, "utf8");
|
|
93
53
|
return pkgJsonPath;
|
|
94
54
|
}
|
|
95
55
|
createPluginsRequireFromDir(dirPath) {
|
|
96
|
-
const pkgJsonPath =
|
|
97
|
-
if (!
|
|
56
|
+
const pkgJsonPath = path.join(dirPath, "package.json");
|
|
57
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
98
58
|
const pkgJson = {
|
|
99
59
|
name: "pagepocket-user-plugins",
|
|
100
60
|
private: true,
|
|
101
61
|
version: "0.0.0"
|
|
102
62
|
};
|
|
103
|
-
|
|
63
|
+
fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkgJson, undefined, 2)}\n`, "utf8");
|
|
104
64
|
}
|
|
105
|
-
return
|
|
65
|
+
return createRequire(pkgJsonPath);
|
|
106
66
|
}
|
|
107
67
|
createPluginsRequire() {
|
|
108
68
|
this.ensurePluginPackageJson();
|
|
@@ -115,8 +75,8 @@ class PluginStore {
|
|
|
115
75
|
readInstalledPackageMeta(pluginName) {
|
|
116
76
|
try {
|
|
117
77
|
const pkgJsonPath = this.resolveInstalledPackageJsonPath(pluginName);
|
|
118
|
-
const text =
|
|
119
|
-
const json =
|
|
78
|
+
const text = fs.readFileSync(pkgJsonPath, "utf8");
|
|
79
|
+
const json = parseJson(text);
|
|
120
80
|
if (!json.ok || !json.value || typeof json.value !== "object") {
|
|
121
81
|
return { name: pluginName };
|
|
122
82
|
}
|
|
@@ -139,8 +99,8 @@ class PluginStore {
|
|
|
139
99
|
*/
|
|
140
100
|
readInstalledDependencyNames() {
|
|
141
101
|
const pkgJsonPath = this.ensurePluginPackageJson();
|
|
142
|
-
const text =
|
|
143
|
-
const parsed =
|
|
102
|
+
const text = fs.readFileSync(pkgJsonPath, "utf8");
|
|
103
|
+
const parsed = parseJson(text);
|
|
144
104
|
if (!parsed.ok || !parsed.value || typeof parsed.value !== "object") {
|
|
145
105
|
return [];
|
|
146
106
|
}
|
|
@@ -157,12 +117,12 @@ class PluginStore {
|
|
|
157
117
|
return this.importResolvedPath(resolved);
|
|
158
118
|
}
|
|
159
119
|
async importResolvedPath(resolved) {
|
|
160
|
-
const mod = await
|
|
120
|
+
const mod = await import(pathToFileURL(resolved).href);
|
|
161
121
|
return isRecord(mod) ? mod : {};
|
|
162
122
|
}
|
|
163
123
|
async instantiatePluginFromSpec(spec) {
|
|
164
124
|
const mod = await this.importPluginModule(spec.name);
|
|
165
|
-
const result =
|
|
125
|
+
const result = validatePluginDefaultExport({
|
|
166
126
|
pluginName: spec.name,
|
|
167
127
|
moduleExports: mod,
|
|
168
128
|
options: spec.options
|
|
@@ -186,10 +146,10 @@ class PluginStore {
|
|
|
186
146
|
this.configService.writeConfig(next);
|
|
187
147
|
}
|
|
188
148
|
hasPlugin(config, pluginName) {
|
|
189
|
-
return config.plugins.some((e) =>
|
|
149
|
+
return config.plugins.some((e) => getPluginNameFromSpec(normalizePluginConfigEntry(e)) === pluginName);
|
|
190
150
|
}
|
|
191
151
|
addPluginToConfig(config, entry) {
|
|
192
|
-
const spec =
|
|
152
|
+
const spec = normalizePluginConfigEntry(entry);
|
|
193
153
|
if (this.hasPlugin(config, spec.name)) {
|
|
194
154
|
return config;
|
|
195
155
|
}
|
|
@@ -197,11 +157,10 @@ class PluginStore {
|
|
|
197
157
|
}
|
|
198
158
|
removePluginFromConfig(config, pluginName) {
|
|
199
159
|
const before = config.plugins;
|
|
200
|
-
const after = before.filter((e) =>
|
|
160
|
+
const after = before.filter((e) => getPluginNameFromSpec(normalizePluginConfigEntry(e)) !== pluginName);
|
|
201
161
|
return {
|
|
202
162
|
config: { ...config, plugins: after },
|
|
203
163
|
removed: after.length !== before.length
|
|
204
164
|
};
|
|
205
165
|
}
|
|
206
166
|
}
|
|
207
|
-
exports.PluginStore = PluginStore;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { readStrategiesFromPackRoot } from "./strategy-pack-read.js";
|
|
4
|
+
const readBuiltinStrategiesUnsafe = () => {
|
|
5
|
+
const req = createRequire(import.meta.url);
|
|
6
|
+
const pkgJsonPath = req.resolve("@pagepocket/builtin-strategy/package.json");
|
|
7
|
+
const packRoot = path.dirname(pkgJsonPath);
|
|
8
|
+
return readStrategiesFromPackRoot(packRoot);
|
|
9
|
+
};
|
|
10
|
+
export const readBuiltinStrategies = () => {
|
|
11
|
+
try {
|
|
12
|
+
return readBuiltinStrategiesUnsafe();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
export const listBuiltinStrategyNames = () => {
|
|
19
|
+
return readBuiltinStrategies().map((strategy) => strategy.name);
|
|
20
|
+
};
|
|
21
|
+
export const readBuiltinStrategy = (name) => {
|
|
22
|
+
return readBuiltinStrategies().find((strategy) => strategy.name === name);
|
|
23
|
+
};
|
|
@@ -1,24 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.ensureNoInstalledVersionConflicts = exports.computeDrift = exports.computeConflicts = exports.collectWantedVersions = exports.uniq = void 0;
|
|
4
|
-
const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
|
|
5
|
-
const uniq = (xs) => [...new Set(xs)];
|
|
6
|
-
exports.uniq = uniq;
|
|
7
|
-
const collectWantedVersions = (strategies) => {
|
|
8
|
-
var _a, _b, _c;
|
|
1
|
+
import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
|
|
2
|
+
export const collectWantedVersions = (strategies) => {
|
|
9
3
|
const wanted = {};
|
|
10
4
|
for (const s of strategies) {
|
|
11
5
|
for (const u of s.units) {
|
|
12
|
-
const pinned =
|
|
13
|
-
wanted[
|
|
14
|
-
|
|
6
|
+
const pinned = parsePinnedSpec(u.ref);
|
|
7
|
+
wanted[pinned.name] ??= {};
|
|
8
|
+
wanted[pinned.name][pinned.version] ??= [];
|
|
15
9
|
wanted[pinned.name][pinned.version].push(s.name);
|
|
16
10
|
}
|
|
17
11
|
}
|
|
18
12
|
return wanted;
|
|
19
13
|
};
|
|
20
|
-
|
|
21
|
-
const computeConflicts = (wanted) => {
|
|
14
|
+
export const computeConflicts = (wanted) => {
|
|
22
15
|
const conflicts = [];
|
|
23
16
|
for (const [name, versions] of Object.entries(wanted)) {
|
|
24
17
|
const uniqueVersions = Object.keys(versions);
|
|
@@ -29,10 +22,9 @@ const computeConflicts = (wanted) => {
|
|
|
29
22
|
}
|
|
30
23
|
return conflicts;
|
|
31
24
|
};
|
|
32
|
-
|
|
33
|
-
const computeDrift = (input) => {
|
|
25
|
+
export const computeDrift = (input) => {
|
|
34
26
|
const items = input.units.flatMap((u) => {
|
|
35
|
-
const pinned =
|
|
27
|
+
const pinned = parsePinnedSpec(u.ref);
|
|
36
28
|
const installedVersion = input.installed[pinned.name];
|
|
37
29
|
if (!installedVersion || installedVersion !== pinned.version) {
|
|
38
30
|
return [
|
|
@@ -47,11 +39,10 @@ const computeDrift = (input) => {
|
|
|
47
39
|
});
|
|
48
40
|
return { strategy: input.strategyName, items };
|
|
49
41
|
};
|
|
50
|
-
|
|
51
|
-
const ensureNoInstalledVersionConflicts = (installed, refs) => {
|
|
42
|
+
export const ensureNoInstalledVersionConflicts = (installed, refs) => {
|
|
52
43
|
const byName = {};
|
|
53
44
|
for (const ref of refs) {
|
|
54
|
-
const pinned =
|
|
45
|
+
const pinned = parsePinnedSpec(ref);
|
|
55
46
|
const already = byName[pinned.name];
|
|
56
47
|
if (already && already !== pinned.version) {
|
|
57
48
|
throw new Error(`Strategy contains conflicting versions for ${pinned.name}: ${already} vs ${pinned.version}`);
|
|
@@ -66,4 +57,3 @@ const ensureNoInstalledVersionConflicts = (installed, refs) => {
|
|
|
66
57
|
}
|
|
67
58
|
}
|
|
68
59
|
};
|
|
69
|
-
exports.ensureNoInstalledVersionConflicts = ensureNoInstalledVersionConflicts;
|
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.withoutStrategyInConfig = exports.withStrategyInConfig = exports.requireStrategyInstalled = exports.listStrategyNamesFromConfig = void 0;
|
|
4
|
-
const uniq = (xs) => [...new Set(xs)];
|
|
5
|
-
const listStrategyNamesFromConfig = (config) => {
|
|
1
|
+
import { uniq } from "../../utils/array.js";
|
|
2
|
+
export const listStrategyNamesFromConfig = (config) => {
|
|
6
3
|
return uniq((config.strategies ?? []).map((s) => s.trim()).filter((s) => s.length > 0));
|
|
7
4
|
};
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const installed = (0, exports.listStrategyNamesFromConfig)(config);
|
|
5
|
+
export const requireStrategyInstalled = (config, name) => {
|
|
6
|
+
const installed = listStrategyNamesFromConfig(config);
|
|
11
7
|
if (!installed.includes(name)) {
|
|
12
8
|
throw new Error(`Strategy not installed: ${name}`);
|
|
13
9
|
}
|
|
14
10
|
};
|
|
15
|
-
|
|
16
|
-
const withStrategyInConfig = (config, name) => {
|
|
11
|
+
export const withStrategyInConfig = (config, name) => {
|
|
17
12
|
const strategies = uniq([...(config.strategies ?? []), name]);
|
|
18
13
|
return { ...config, strategies };
|
|
19
14
|
};
|
|
20
|
-
|
|
21
|
-
const withoutStrategyInConfig = (config, name) => {
|
|
15
|
+
export const withoutStrategyInConfig = (config, name) => {
|
|
22
16
|
const strategies = (config.strategies ?? []).filter((s) => s !== name);
|
|
23
17
|
return { ...config, strategies };
|
|
24
18
|
};
|
|
25
|
-
exports.withoutStrategyInConfig = withoutStrategyInConfig;
|
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.fetchStrategyFile = void 0;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const parse_json_1 = require("../../utils/parse-json");
|
|
10
|
-
const normalize_argv_1 = require("../../utils/normalize-argv");
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseJson } from "../../utils/parse-json.js";
|
|
4
|
+
import { isUrlLike } from "../../utils/normalize-argv.js";
|
|
11
5
|
const isRecord = (value) => {
|
|
12
6
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13
7
|
};
|
|
@@ -31,15 +25,15 @@ const isStrategyFile = (value) => {
|
|
|
31
25
|
return true;
|
|
32
26
|
};
|
|
33
27
|
const readTextFromPath = (p) => {
|
|
34
|
-
const full =
|
|
35
|
-
return
|
|
28
|
+
const full = path.resolve(p);
|
|
29
|
+
return fs.readFileSync(full, "utf8");
|
|
36
30
|
};
|
|
37
|
-
const fetchStrategyFile = async (input) => {
|
|
31
|
+
export const fetchStrategyFile = async (input) => {
|
|
38
32
|
const raw = input.trim();
|
|
39
33
|
if (!raw) {
|
|
40
34
|
throw new Error("strategy source is empty");
|
|
41
35
|
}
|
|
42
|
-
if (
|
|
36
|
+
if (isUrlLike(raw)) {
|
|
43
37
|
const url = new URL(raw);
|
|
44
38
|
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
45
39
|
throw new Error(`Unsupported strategy URL protocol: ${url.protocol}`);
|
|
@@ -49,7 +43,7 @@ const fetchStrategyFile = async (input) => {
|
|
|
49
43
|
throw new Error(`Failed to fetch strategy: ${res.status} ${res.statusText}`);
|
|
50
44
|
}
|
|
51
45
|
const text = await res.text();
|
|
52
|
-
const parsed =
|
|
46
|
+
const parsed = parseJson(text);
|
|
53
47
|
if (!parsed.ok) {
|
|
54
48
|
throw parsed.error;
|
|
55
49
|
}
|
|
@@ -59,13 +53,12 @@ const fetchStrategyFile = async (input) => {
|
|
|
59
53
|
return { strategy: parsed.value, source: { type: "url", value: url.toString() } };
|
|
60
54
|
}
|
|
61
55
|
const text = readTextFromPath(raw);
|
|
62
|
-
const parsed =
|
|
56
|
+
const parsed = parseJson(text);
|
|
63
57
|
if (!parsed.ok) {
|
|
64
58
|
throw parsed.error;
|
|
65
59
|
}
|
|
66
60
|
if (!isStrategyFile(parsed.value)) {
|
|
67
61
|
throw new Error(`Invalid strategy JSON from file: ${raw}`);
|
|
68
62
|
}
|
|
69
|
-
return { strategy: parsed.value, source: { type: "file", value:
|
|
63
|
+
return { strategy: parsed.value, source: { type: "file", value: path.resolve(raw) } };
|
|
70
64
|
};
|
|
71
|
-
exports.fetchStrategyFile = fetchStrategyFile;
|
|
@@ -1,12 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.writeJsonAtomic = exports.readStrategyFile = exports.getStrategyPath = exports.getStrategiesDir = void 0;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const parse_json_1 = require("../../utils/parse-json");
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseJson } from "../../utils/parse-json.js";
|
|
10
4
|
const isRecord = (value) => {
|
|
11
5
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
12
6
|
};
|
|
@@ -29,17 +23,15 @@ const isStrategyFile = (value) => {
|
|
|
29
23
|
}
|
|
30
24
|
return true;
|
|
31
25
|
};
|
|
32
|
-
const getStrategiesDir = (configService) => {
|
|
33
|
-
return
|
|
26
|
+
export const getStrategiesDir = (configService) => {
|
|
27
|
+
return path.join(configService.getConfigDir(), "strategies");
|
|
34
28
|
};
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return node_path_1.default.join((0, exports.getStrategiesDir)(configService), `${name}.json`);
|
|
29
|
+
export const getStrategyPath = (configService, name) => {
|
|
30
|
+
return path.join(getStrategiesDir(configService), `${name}.json`);
|
|
38
31
|
};
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
const parsed = (0, parse_json_1.parseJson)(text);
|
|
32
|
+
export const readStrategyFile = (filePath) => {
|
|
33
|
+
const text = fs.readFileSync(filePath, "utf8");
|
|
34
|
+
const parsed = parseJson(text);
|
|
43
35
|
if (!parsed.ok) {
|
|
44
36
|
throw parsed.error;
|
|
45
37
|
}
|
|
@@ -48,12 +40,10 @@ const readStrategyFile = (filePath) => {
|
|
|
48
40
|
}
|
|
49
41
|
return parsed.value;
|
|
50
42
|
};
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
node_fs_1.default.mkdirSync(dir, { recursive: true });
|
|
43
|
+
export const writeJsonAtomic = (filePath, value) => {
|
|
44
|
+
const dir = path.dirname(filePath);
|
|
45
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
55
46
|
const tmpPath = `${filePath}.tmp`;
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
fs.writeFileSync(tmpPath, `${JSON.stringify(value, undefined, 2)}\n`, "utf8");
|
|
48
|
+
fs.renameSync(tmpPath, filePath);
|
|
58
49
|
};
|
|
59
|
-
exports.writeJsonAtomic = writeJsonAtomic;
|