@pagepocket/cli 0.11.0 → 0.12.0
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 +80 -118
- 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 +14 -22
- 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 +15 -21
- package/dist/commands/strategy/ls.js +31 -17
- 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 +30 -36
- package/dist/services/load-configured-plugins.js +8 -12
- package/dist/services/plugin-installer.js +14 -20
- package/dist/services/plugin-store.js +36 -79
- package/dist/services/strategy/builtin-strategy-registry.js +14 -32
- package/dist/services/strategy/strategy-analyze.js +14 -22
- package/dist/services/strategy/strategy-config.js +10 -17
- package/dist/services/strategy/strategy-fetch.js +12 -21
- package/dist/services/strategy/strategy-io.js +14 -30
- package/dist/services/strategy/strategy-normalize.js +9 -15
- package/dist/services/strategy/strategy-pack-read.js +12 -21
- package/dist/services/strategy/strategy-pack-store.js +12 -18
- package/dist/services/strategy/strategy-service.js +122 -117
- package/dist/services/strategy/types.js +1 -2
- package/dist/services/units/unit-store.js +16 -20
- package/dist/services/units/unit-validate.js +23 -11
- package/dist/services/user-packages/parse-pinned-spec.js +7 -17
- package/dist/services/user-packages/user-package-installer.js +8 -13
- package/dist/services/user-packages/user-package-store.js +27 -65
- package/dist/stages/prepare-output.js +6 -13
- package/dist/units/network-observer-unit.js +7 -10
- package/dist/utils/array.js +1 -7
- 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 +5 -11
- package/dist/utils/validate-plugin-default-export.js +1 -5
- package/dist/utils/with-spinner.js +3 -10
- package/dist/view.js +14 -21
- package/package.json +16 -12
package/dist/lib/filename.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.safeFilename = void 0;
|
|
4
|
-
const safeFilename = (input) => {
|
|
1
|
+
export const safeFilename = (input) => {
|
|
5
2
|
const trimmed = input.trim();
|
|
6
3
|
if (!trimmed) {
|
|
7
4
|
return "snapshot";
|
|
@@ -11,4 +8,3 @@ const safeFilename = (input) => {
|
|
|
11
8
|
.replace(/^_+|_+$/g, "")
|
|
12
9
|
.slice(0, 120) || "snapshot");
|
|
13
10
|
};
|
|
14
|
-
exports.safeFilename = safeFilename;
|
|
@@ -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
|
|
24
|
-
return
|
|
18
|
+
const envPathsResult = envPaths(this.appName, { suffix: "" });
|
|
19
|
+
return envPathsResult.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
|
|
33
|
-
return
|
|
27
|
+
const envPathsResult = envPaths(this.appName, { suffix: "" });
|
|
28
|
+
return envPathsResult.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);
|
|
@@ -78,13 +73,13 @@ class ConfigService {
|
|
|
78
73
|
}
|
|
79
74
|
return undefined;
|
|
80
75
|
})
|
|
81
|
-
.filter((
|
|
76
|
+
.filter((pluginEntry) => typeof pluginEntry !== "undefined")
|
|
82
77
|
: [];
|
|
83
78
|
const strategiesRaw = value.strategies;
|
|
84
79
|
const strategies = Array.isArray(strategiesRaw)
|
|
85
80
|
? strategiesRaw
|
|
86
|
-
.map((
|
|
87
|
-
.filter((
|
|
81
|
+
.map((strategyName) => (typeof strategyName === "string" ? strategyName.trim() : ""))
|
|
82
|
+
.filter((strategyName) => strategyName.length > 0)
|
|
88
83
|
: [];
|
|
89
84
|
const packsRaw = value.strategyPacks;
|
|
90
85
|
const strategyPacks = Array.isArray(packsRaw)
|
|
@@ -103,7 +98,7 @@ class ConfigService {
|
|
|
103
98
|
}
|
|
104
99
|
return undefined;
|
|
105
100
|
})
|
|
106
|
-
.filter((
|
|
101
|
+
.filter((strategyPackEntry) => Boolean(strategyPackEntry))
|
|
107
102
|
: [];
|
|
108
103
|
return {
|
|
109
104
|
plugins,
|
|
@@ -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,16 +7,16 @@ 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
|
|
10
|
+
const result = spawnSync(cmd, args, {
|
|
14
11
|
cwd: installDir,
|
|
15
12
|
stdio: "inherit",
|
|
16
13
|
shell: false
|
|
17
14
|
});
|
|
18
|
-
if (
|
|
19
|
-
return { ok: false, error:
|
|
15
|
+
if (result.error) {
|
|
16
|
+
return { ok: false, error: result.error };
|
|
20
17
|
}
|
|
21
|
-
if (typeof
|
|
22
|
-
return { ok: false, error: new Error(`${cmd} exited with code ${
|
|
18
|
+
if (typeof result.status === "number" && result.status !== 0) {
|
|
19
|
+
return { ok: false, error: new Error(`${cmd} exited with code ${result.status}`) };
|
|
23
20
|
}
|
|
24
21
|
return { ok: true };
|
|
25
22
|
};
|
|
@@ -33,39 +30,37 @@ 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
|
|
54
|
+
const result = spawnSync(cmd, args, {
|
|
60
55
|
cwd: installDir,
|
|
61
56
|
stdio: "inherit",
|
|
62
57
|
shell: false
|
|
63
58
|
});
|
|
64
|
-
if (
|
|
65
|
-
return { ok: false, error:
|
|
59
|
+
if (result.error) {
|
|
60
|
+
return { ok: false, error: result.error };
|
|
66
61
|
}
|
|
67
|
-
if (typeof
|
|
68
|
-
return { ok: false, error: new Error(`${cmd} exited with code ${
|
|
62
|
+
if (typeof result.status === "number" && result.status !== 0) {
|
|
63
|
+
return { ok: false, error: new Error(`${cmd} exited with code ${result.status}`) };
|
|
69
64
|
}
|
|
70
65
|
return { ok: true };
|
|
71
66
|
};
|
|
@@ -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,22 +14,17 @@ const normalizePluginConfigEntry = (entry) => {
|
|
|
53
14
|
...(typeof entry.options === "undefined" ? {} : { options: entry.options })
|
|
54
15
|
};
|
|
55
16
|
};
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const isRecord = (value) => {
|
|
60
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
61
|
-
};
|
|
62
|
-
const isCallable = (value) => {
|
|
63
|
-
return typeof value === "function";
|
|
64
|
-
};
|
|
17
|
+
export const getPluginNameFromSpec = (spec) => spec.name;
|
|
18
|
+
const isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
19
|
+
const isCallable = (value) => typeof value === "function";
|
|
65
20
|
const isStringRecord = (value) => {
|
|
66
21
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
67
22
|
return false;
|
|
68
23
|
}
|
|
69
|
-
return Object.values(value).every((
|
|
24
|
+
return Object.values(value).every((entryValue) => typeof entryValue === "string");
|
|
70
25
|
};
|
|
71
|
-
class PluginStore {
|
|
26
|
+
export class PluginStore {
|
|
27
|
+
configService;
|
|
72
28
|
constructor(configService) {
|
|
73
29
|
this.configService = configService;
|
|
74
30
|
}
|
|
@@ -76,12 +32,12 @@ class PluginStore {
|
|
|
76
32
|
return this.configService.getPluginsInstallDir();
|
|
77
33
|
}
|
|
78
34
|
ensureInstallDir() {
|
|
79
|
-
|
|
35
|
+
fs.mkdirSync(this.getInstallDir(), { recursive: true });
|
|
80
36
|
}
|
|
81
37
|
ensurePluginPackageJson() {
|
|
82
38
|
this.ensureInstallDir();
|
|
83
|
-
const pkgJsonPath =
|
|
84
|
-
if (
|
|
39
|
+
const pkgJsonPath = path.join(this.getInstallDir(), "package.json");
|
|
40
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
85
41
|
return pkgJsonPath;
|
|
86
42
|
}
|
|
87
43
|
const pkgJson = {
|
|
@@ -89,20 +45,20 @@ class PluginStore {
|
|
|
89
45
|
private: true,
|
|
90
46
|
version: "0.0.0"
|
|
91
47
|
};
|
|
92
|
-
|
|
48
|
+
fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkgJson, undefined, 2)}\n`, "utf8");
|
|
93
49
|
return pkgJsonPath;
|
|
94
50
|
}
|
|
95
51
|
createPluginsRequireFromDir(dirPath) {
|
|
96
|
-
const pkgJsonPath =
|
|
97
|
-
if (!
|
|
52
|
+
const pkgJsonPath = path.join(dirPath, "package.json");
|
|
53
|
+
if (!fs.existsSync(pkgJsonPath)) {
|
|
98
54
|
const pkgJson = {
|
|
99
55
|
name: "pagepocket-user-plugins",
|
|
100
56
|
private: true,
|
|
101
57
|
version: "0.0.0"
|
|
102
58
|
};
|
|
103
|
-
|
|
59
|
+
fs.writeFileSync(pkgJsonPath, `${JSON.stringify(pkgJson, undefined, 2)}\n`, "utf8");
|
|
104
60
|
}
|
|
105
|
-
return
|
|
61
|
+
return createRequire(pkgJsonPath);
|
|
106
62
|
}
|
|
107
63
|
createPluginsRequire() {
|
|
108
64
|
this.ensurePluginPackageJson();
|
|
@@ -115,16 +71,18 @@ class PluginStore {
|
|
|
115
71
|
readInstalledPackageMeta(pluginName) {
|
|
116
72
|
try {
|
|
117
73
|
const pkgJsonPath = this.resolveInstalledPackageJsonPath(pluginName);
|
|
118
|
-
const text =
|
|
119
|
-
const json =
|
|
74
|
+
const text = fs.readFileSync(pkgJsonPath, "utf8");
|
|
75
|
+
const json = parseJson(text);
|
|
120
76
|
if (!json.ok || !json.value || typeof json.value !== "object") {
|
|
121
77
|
return { name: pluginName };
|
|
122
78
|
}
|
|
123
|
-
const
|
|
79
|
+
const packageJsonRecord = json.value;
|
|
124
80
|
return {
|
|
125
|
-
name: typeof
|
|
126
|
-
description: typeof
|
|
127
|
-
|
|
81
|
+
name: typeof packageJsonRecord.name === "string" ? packageJsonRecord.name : pluginName,
|
|
82
|
+
description: typeof packageJsonRecord.description === "string"
|
|
83
|
+
? packageJsonRecord.description
|
|
84
|
+
: undefined,
|
|
85
|
+
version: typeof packageJsonRecord.version === "string" ? packageJsonRecord.version : undefined
|
|
128
86
|
};
|
|
129
87
|
}
|
|
130
88
|
catch {
|
|
@@ -139,8 +97,8 @@ class PluginStore {
|
|
|
139
97
|
*/
|
|
140
98
|
readInstalledDependencyNames() {
|
|
141
99
|
const pkgJsonPath = this.ensurePluginPackageJson();
|
|
142
|
-
const text =
|
|
143
|
-
const parsed =
|
|
100
|
+
const text = fs.readFileSync(pkgJsonPath, "utf8");
|
|
101
|
+
const parsed = parseJson(text);
|
|
144
102
|
if (!parsed.ok || !parsed.value || typeof parsed.value !== "object") {
|
|
145
103
|
return [];
|
|
146
104
|
}
|
|
@@ -157,12 +115,12 @@ class PluginStore {
|
|
|
157
115
|
return this.importResolvedPath(resolved);
|
|
158
116
|
}
|
|
159
117
|
async importResolvedPath(resolved) {
|
|
160
|
-
const mod = await
|
|
118
|
+
const mod = await import(pathToFileURL(resolved).href);
|
|
161
119
|
return isRecord(mod) ? mod : {};
|
|
162
120
|
}
|
|
163
121
|
async instantiatePluginFromSpec(spec) {
|
|
164
122
|
const mod = await this.importPluginModule(spec.name);
|
|
165
|
-
const result =
|
|
123
|
+
const result = validatePluginDefaultExport({
|
|
166
124
|
pluginName: spec.name,
|
|
167
125
|
moduleExports: mod,
|
|
168
126
|
options: spec.options
|
|
@@ -186,10 +144,10 @@ class PluginStore {
|
|
|
186
144
|
this.configService.writeConfig(next);
|
|
187
145
|
}
|
|
188
146
|
hasPlugin(config, pluginName) {
|
|
189
|
-
return config.plugins.some((
|
|
147
|
+
return config.plugins.some((pluginEntry) => getPluginNameFromSpec(normalizePluginConfigEntry(pluginEntry)) === pluginName);
|
|
190
148
|
}
|
|
191
149
|
addPluginToConfig(config, entry) {
|
|
192
|
-
const spec =
|
|
150
|
+
const spec = normalizePluginConfigEntry(entry);
|
|
193
151
|
if (this.hasPlugin(config, spec.name)) {
|
|
194
152
|
return config;
|
|
195
153
|
}
|
|
@@ -197,11 +155,10 @@ class PluginStore {
|
|
|
197
155
|
}
|
|
198
156
|
removePluginFromConfig(config, pluginName) {
|
|
199
157
|
const before = config.plugins;
|
|
200
|
-
const after = before.filter((
|
|
158
|
+
const after = before.filter((pluginEntry) => getPluginNameFromSpec(normalizePluginConfigEntry(pluginEntry)) !== pluginName);
|
|
201
159
|
return {
|
|
202
160
|
config: { ...config, plugins: after },
|
|
203
161
|
removed: after.length !== before.length
|
|
204
162
|
};
|
|
205
163
|
}
|
|
206
164
|
}
|
|
207
|
-
exports.PluginStore = PluginStore;
|
|
@@ -1,32 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
};
|
|
16
|
-
const readBuiltinStrategies = () => {
|
|
17
|
-
try {
|
|
18
|
-
return readBuiltinStrategiesUnsafe();
|
|
19
|
-
}
|
|
20
|
-
catch {
|
|
21
|
-
return [];
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
exports.readBuiltinStrategies = readBuiltinStrategies;
|
|
25
|
-
const listBuiltinStrategyNames = () => {
|
|
26
|
-
return (0, exports.readBuiltinStrategies)().map((strategy) => strategy.name);
|
|
27
|
-
};
|
|
28
|
-
exports.listBuiltinStrategyNames = listBuiltinStrategyNames;
|
|
29
|
-
const readBuiltinStrategy = (name) => {
|
|
30
|
-
return (0, exports.readBuiltinStrategies)().find((strategy) => strategy.name === name);
|
|
31
|
-
};
|
|
32
|
-
exports.readBuiltinStrategy = readBuiltinStrategy;
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { MemoryCache } from "@pagepocket/shared";
|
|
4
|
+
import { readStrategiesFromPackRoot } from "./strategy-pack-read.js";
|
|
5
|
+
const BUILTIN_KEY = "builtin";
|
|
6
|
+
const cache = new MemoryCache();
|
|
7
|
+
const resolveBuiltinPackRoot = () => {
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const packageJsonPath = require.resolve("@pagepocket/builtin-strategy/package.json");
|
|
10
|
+
return path.dirname(packageJsonPath);
|
|
11
|
+
};
|
|
12
|
+
const loadBuiltinStrategies = () => cache.getOrSet(BUILTIN_KEY, () => readStrategiesFromPackRoot(resolveBuiltinPackRoot()));
|
|
13
|
+
export const listBuiltinStrategyNames = () => loadBuiltinStrategies().map((strategy) => strategy.name);
|
|
14
|
+
export const readBuiltinStrategy = (name) => loadBuiltinStrategies().find((strategy) => strategy.name === name);
|
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.ensureNoInstalledVersionConflicts = exports.computeDrift = exports.computeConflicts = exports.collectWantedVersions = void 0;
|
|
4
|
-
const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
|
|
5
|
-
const collectWantedVersions = (strategies) => {
|
|
6
|
-
var _a, _b, _c;
|
|
1
|
+
import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
|
|
2
|
+
export const collectWantedVersions = (strategies) => {
|
|
7
3
|
const wanted = {};
|
|
8
|
-
for (const
|
|
9
|
-
for (const
|
|
10
|
-
const pinned =
|
|
11
|
-
wanted[
|
|
12
|
-
|
|
13
|
-
wanted[pinned.name][pinned.version].push(
|
|
4
|
+
for (const strategy of strategies) {
|
|
5
|
+
for (const unit of strategy.units) {
|
|
6
|
+
const pinned = parsePinnedSpec(unit.ref);
|
|
7
|
+
wanted[pinned.name] ??= {};
|
|
8
|
+
wanted[pinned.name][pinned.version] ??= [];
|
|
9
|
+
wanted[pinned.name][pinned.version].push(strategy.name);
|
|
14
10
|
}
|
|
15
11
|
}
|
|
16
12
|
return wanted;
|
|
17
13
|
};
|
|
18
|
-
|
|
19
|
-
const computeConflicts = (wanted) => {
|
|
14
|
+
export const computeConflicts = (wanted) => {
|
|
20
15
|
const conflicts = [];
|
|
21
16
|
for (const [name, versions] of Object.entries(wanted)) {
|
|
22
17
|
const uniqueVersions = Object.keys(versions);
|
|
@@ -27,10 +22,9 @@ const computeConflicts = (wanted) => {
|
|
|
27
22
|
}
|
|
28
23
|
return conflicts;
|
|
29
24
|
};
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(u.ref);
|
|
25
|
+
export const computeDrift = (input) => {
|
|
26
|
+
const items = input.units.flatMap((unit) => {
|
|
27
|
+
const pinned = parsePinnedSpec(unit.ref);
|
|
34
28
|
const installedVersion = input.installed[pinned.name];
|
|
35
29
|
if (!installedVersion || installedVersion !== pinned.version) {
|
|
36
30
|
return [
|
|
@@ -45,11 +39,10 @@ const computeDrift = (input) => {
|
|
|
45
39
|
});
|
|
46
40
|
return { strategy: input.strategyName, items };
|
|
47
41
|
};
|
|
48
|
-
|
|
49
|
-
const ensureNoInstalledVersionConflicts = (installed, refs) => {
|
|
42
|
+
export const ensureNoInstalledVersionConflicts = (installed, refs) => {
|
|
50
43
|
const byName = {};
|
|
51
44
|
for (const ref of refs) {
|
|
52
|
-
const pinned =
|
|
45
|
+
const pinned = parsePinnedSpec(ref);
|
|
53
46
|
const already = byName[pinned.name];
|
|
54
47
|
if (already && already !== pinned.version) {
|
|
55
48
|
throw new Error(`Strategy contains conflicting versions for ${pinned.name}: ${already} vs ${pinned.version}`);
|
|
@@ -64,4 +57,3 @@ const ensureNoInstalledVersionConflicts = (installed, refs) => {
|
|
|
64
57
|
}
|
|
65
58
|
}
|
|
66
59
|
};
|
|
67
|
-
exports.ensureNoInstalledVersionConflicts = ensureNoInstalledVersionConflicts;
|
|
@@ -1,25 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
exports.listStrategyNamesFromConfig = listStrategyNamesFromConfig;
|
|
9
|
-
const requireStrategyInstalled = (config, name) => {
|
|
10
|
-
const installed = (0, exports.listStrategyNamesFromConfig)(config);
|
|
1
|
+
import { uniq } from "../../utils/array.js";
|
|
2
|
+
export const listStrategyNamesFromConfig = (config) => uniq((config.strategies ?? [])
|
|
3
|
+
.map((strategyName) => strategyName.trim())
|
|
4
|
+
.filter((strategyName) => strategyName.length > 0));
|
|
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
|
|
17
|
-
const strategies = (0, array_1.uniq)([...(config.strategies ?? []), name]);
|
|
11
|
+
export const withStrategyInConfig = (config, name) => {
|
|
12
|
+
const strategies = uniq([...(config.strategies ?? []), name]);
|
|
18
13
|
return { ...config, strategies };
|
|
19
14
|
};
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
const strategies = (config.strategies ?? []).filter((s) => s !== name);
|
|
15
|
+
export const withoutStrategyInConfig = (config, name) => {
|
|
16
|
+
const strategies = (config.strategies ?? []).filter((strategyName) => strategyName !== name);
|
|
23
17
|
return { ...config, strategies };
|
|
24
18
|
};
|
|
25
|
-
exports.withoutStrategyInConfig = withoutStrategyInConfig;
|