@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.
Files changed (49) hide show
  1. package/dist/commands/archive.js +146 -76
  2. package/dist/commands/plugin/add.js +19 -25
  3. package/dist/commands/plugin/doctor.js +22 -28
  4. package/dist/commands/plugin/ls.js +16 -22
  5. package/dist/commands/plugin/prune.js +13 -19
  6. package/dist/commands/plugin/remove.js +16 -22
  7. package/dist/commands/plugin/set.js +13 -19
  8. package/dist/commands/plugin/uninstall.js +29 -35
  9. package/dist/commands/plugin/update.js +22 -28
  10. package/dist/commands/strategy/add.js +14 -20
  11. package/dist/commands/strategy/doctor.js +11 -17
  12. package/dist/commands/strategy/ls.js +22 -0
  13. package/dist/commands/strategy/pin.js +10 -16
  14. package/dist/commands/strategy/remove.js +10 -16
  15. package/dist/commands/strategy/update.js +21 -27
  16. package/dist/commands/view.js +36 -42
  17. package/dist/index.js +9 -7
  18. package/dist/lib/filename.js +1 -5
  19. package/dist/services/config-service.js +24 -30
  20. package/dist/services/load-configured-plugins.js +8 -12
  21. package/dist/services/plugin-installer.js +6 -12
  22. package/dist/services/plugin-store.js +27 -68
  23. package/dist/services/strategy/builtin-strategy-registry.js +23 -0
  24. package/dist/services/strategy/strategy-analyze.js +10 -20
  25. package/dist/services/strategy/strategy-config.js +6 -13
  26. package/dist/services/strategy/strategy-fetch.js +11 -18
  27. package/dist/services/strategy/strategy-io.js +15 -25
  28. package/dist/services/strategy/strategy-normalize.js +4 -8
  29. package/dist/services/strategy/strategy-pack-read.js +10 -17
  30. package/dist/services/strategy/strategy-pack-store.js +12 -18
  31. package/dist/services/strategy/strategy-service.js +79 -82
  32. package/dist/services/strategy/types.js +1 -2
  33. package/dist/services/units/unit-store.js +16 -20
  34. package/dist/services/units/unit-validate.js +20 -5
  35. package/dist/services/user-packages/parse-pinned-spec.js +6 -6
  36. package/dist/services/user-packages/user-package-installer.js +4 -9
  37. package/dist/services/user-packages/user-package-store.js +19 -57
  38. package/dist/stages/prepare-output.js +6 -13
  39. package/dist/units/network-observer-unit.js +7 -10
  40. package/dist/utils/array.js +3 -0
  41. package/dist/utils/normalize-argv.js +3 -8
  42. package/dist/utils/parse-json.js +1 -5
  43. package/dist/utils/parse-plugin-options.js +1 -5
  44. package/dist/utils/parse-plugin-spec.js +6 -6
  45. package/dist/utils/validate-plugin-default-export.js +1 -5
  46. package/dist/utils/with-spinner.js +3 -10
  47. package/dist/view.js +12 -19
  48. package/package.json +12 -11
  49. package/dist/services/strategy/read-installed-package-version.js +0 -28
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeStrategyUnits = void 0;
4
- const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
1
+ import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
5
2
  const isRecord = (value) => {
6
3
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
7
4
  };
@@ -23,7 +20,7 @@ const isJsonValue = (value) => {
23
20
  };
24
21
  const normalizeUnitSpec = (spec, idx) => {
25
22
  if (typeof spec === "string") {
26
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
23
+ const pinned = parsePinnedSpec(spec);
27
24
  return { ref: pinned.spec, args: [] };
28
25
  }
29
26
  if (!isRecord(spec)) {
@@ -33,7 +30,7 @@ const normalizeUnitSpec = (spec, idx) => {
33
30
  if (typeof ref !== "string") {
34
31
  throw new Error(`Invalid unit ref at index ${idx}`);
35
32
  }
36
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(ref);
33
+ const pinned = parsePinnedSpec(ref);
37
34
  const argsRaw = spec.args;
38
35
  const args = typeof argsRaw === "undefined" ? [] : argsRaw;
39
36
  if (!Array.isArray(args)) {
@@ -44,8 +41,7 @@ const normalizeUnitSpec = (spec, idx) => {
44
41
  }
45
42
  return { ref: pinned.spec, args };
46
43
  };
47
- const normalizeStrategyUnits = (strategy) => {
44
+ export const normalizeStrategyUnits = (strategy) => {
48
45
  const units = strategy.pipeline.units;
49
46
  return units.map((spec, idx) => normalizeUnitSpec(spec, idx));
50
47
  };
51
- exports.normalizeStrategyUnits = normalizeStrategyUnits;
@@ -1,12 +1,6 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.readStrategiesFromPackRoot = 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,19 +23,19 @@ const isStrategyFile = (value) => {
29
23
  }
30
24
  return true;
31
25
  };
32
- const readStrategiesFromPackRoot = (packRoot) => {
33
- const strategiesDir = node_path_1.default.join(packRoot, "strategies");
34
- if (!node_fs_1.default.existsSync(strategiesDir)) {
26
+ export const readStrategiesFromPackRoot = (packRoot) => {
27
+ const strategiesDir = path.join(packRoot, "strategies");
28
+ if (!fs.existsSync(strategiesDir)) {
35
29
  return [];
36
30
  }
37
- const fileNames = node_fs_1.default
31
+ const fileNames = fs
38
32
  .readdirSync(strategiesDir)
39
33
  .filter((f) => f.endsWith(".strategy.json"))
40
34
  .sort((a, b) => a.localeCompare(b));
41
35
  return fileNames.map((fileName) => {
42
- const filePath = node_path_1.default.join(strategiesDir, fileName);
43
- const text = node_fs_1.default.readFileSync(filePath, "utf8");
44
- const parsed = (0, parse_json_1.parseJson)(text);
36
+ const filePath = path.join(strategiesDir, fileName);
37
+ const text = fs.readFileSync(filePath, "utf8");
38
+ const parsed = parseJson(text);
45
39
  if (!parsed.ok) {
46
40
  throw parsed.error;
47
41
  }
@@ -51,4 +45,3 @@ const readStrategiesFromPackRoot = (packRoot) => {
51
45
  return parsed.value;
52
46
  });
53
47
  };
54
- exports.readStrategiesFromPackRoot = readStrategiesFromPackRoot;
@@ -1,19 +1,14 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StrategyPackStore = void 0;
7
- const node_path_1 = __importDefault(require("node:path"));
8
- const user_package_installer_1 = require("../user-packages/user-package-installer");
9
- const user_package_installer_2 = require("../user-packages/user-package-installer");
10
- const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
11
- const user_package_store_1 = require("../user-packages/user-package-store");
1
+ import path from "node:path";
2
+ import { installPinnedPackage } from "../user-packages/user-package-installer.js";
3
+ import { updatePackageToLatest } from "../user-packages/user-package-installer.js";
4
+ import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
5
+ import { UserPackageStore } from "../user-packages/user-package-store.js";
12
6
  const STRATEGY_PACKS_KIND = "strategy-packs";
13
7
  const STRATEGY_PACKS_PACKAGE_JSON_NAME = "pagepocket-user-strategy-packs";
14
- class StrategyPackStore {
8
+ export class StrategyPackStore {
9
+ store;
15
10
  constructor(configService) {
16
- this.store = new user_package_store_1.UserPackageStore(configService, STRATEGY_PACKS_KIND);
11
+ this.store = new UserPackageStore(configService, STRATEGY_PACKS_KIND);
17
12
  }
18
13
  getInstallDir() {
19
14
  return this.store.getInstallDir();
@@ -22,15 +17,15 @@ class StrategyPackStore {
22
17
  return this.store.readInstalledDependencyVersions(STRATEGY_PACKS_PACKAGE_JSON_NAME);
23
18
  }
24
19
  installPinned(spec) {
25
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
26
- (0, user_package_installer_1.installPinnedPackage)(this.store, {
20
+ const pinned = parsePinnedSpec(spec);
21
+ installPinnedPackage(this.store, {
27
22
  packageJsonName: STRATEGY_PACKS_PACKAGE_JSON_NAME,
28
23
  packageSpec: pinned.spec
29
24
  });
30
25
  return pinned;
31
26
  }
32
27
  updateToLatest(packageName) {
33
- (0, user_package_installer_2.updatePackageToLatest)(this.store, {
28
+ updatePackageToLatest(this.store, {
34
29
  packageJsonName: STRATEGY_PACKS_PACKAGE_JSON_NAME,
35
30
  packageName
36
31
  });
@@ -39,7 +34,6 @@ class StrategyPackStore {
39
34
  this.store.ensureInstallDirPackageJson(STRATEGY_PACKS_PACKAGE_JSON_NAME);
40
35
  const req = this.store.createRequire(STRATEGY_PACKS_PACKAGE_JSON_NAME);
41
36
  const pkgJsonPath = req.resolve(`${packageName}/package.json`);
42
- return node_path_1.default.dirname(pkgJsonPath);
37
+ return path.dirname(pkgJsonPath);
43
38
  }
44
39
  }
45
- exports.StrategyPackStore = StrategyPackStore;
@@ -1,41 +1,39 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StrategyService = void 0;
7
- const node_fs_1 = __importDefault(require("node:fs"));
8
- const config_service_1 = require("../config-service");
9
- const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
10
- const unit_store_1 = require("../units/unit-store");
11
- const strategy_analyze_1 = require("./strategy-analyze");
12
- const strategy_config_1 = require("./strategy-config");
13
- const strategy_fetch_1 = require("./strategy-fetch");
14
- const strategy_io_1 = require("./strategy-io");
15
- const strategy_normalize_1 = require("./strategy-normalize");
16
- const strategy_pack_read_1 = require("./strategy-pack-read");
17
- const strategy_pack_store_1 = require("./strategy-pack-store");
18
- class StrategyService {
19
- constructor(configService = new config_service_1.ConfigService()) {
1
+ import fs from "node:fs";
2
+ import { ConfigService } from "../config-service.js";
3
+ import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
4
+ import { UnitStore } from "../units/unit-store.js";
5
+ import { uniq } from "../../utils/array.js";
6
+ import { collectWantedVersions, computeConflicts, computeDrift, ensureNoInstalledVersionConflicts } from "./strategy-analyze.js";
7
+ import { listStrategyNamesFromConfig, requireStrategyInstalled, withStrategyInConfig, withoutStrategyInConfig } from "./strategy-config.js";
8
+ import { fetchStrategyFile } from "./strategy-fetch.js";
9
+ import { getStrategyPath, getStrategiesDir, readStrategyFile, writeJsonAtomic } from "./strategy-io.js";
10
+ import { normalizeStrategyUnits } from "./strategy-normalize.js";
11
+ import { readStrategiesFromPackRoot } from "./strategy-pack-read.js";
12
+ import { StrategyPackStore } from "./strategy-pack-store.js";
13
+ export class StrategyService {
14
+ configService;
15
+ unitStore;
16
+ packStore;
17
+ constructor(configService = new ConfigService()) {
20
18
  this.configService = configService;
21
- this.unitStore = new unit_store_1.UnitStore(configService);
22
- this.packStore = new strategy_pack_store_1.StrategyPackStore(configService);
19
+ this.unitStore = new UnitStore(configService);
20
+ this.packStore = new StrategyPackStore(configService);
23
21
  }
24
22
  ensureConfigFileExists() {
25
23
  return this.configService.ensureConfigFileExists();
26
24
  }
27
25
  getStrategiesDir() {
28
- return (0, strategy_io_1.getStrategiesDir)(this.configService);
26
+ return getStrategiesDir(this.configService);
29
27
  }
30
28
  getStrategyPath(name) {
31
- return (0, strategy_io_1.getStrategyPath)(this.configService, name);
29
+ return getStrategyPath(this.configService, name);
32
30
  }
33
31
  readStrategy(name) {
34
- return (0, strategy_io_1.readStrategyFile)(this.getStrategyPath(name));
32
+ return readStrategyFile(this.getStrategyPath(name));
35
33
  }
36
34
  listInstalledStrategyNames() {
37
35
  const config = this.configService.readConfigOrDefault();
38
- return (0, strategy_config_1.listStrategyNamesFromConfig)(config);
36
+ return listStrategyNamesFromConfig(config);
39
37
  }
40
38
  async addStrategy(input) {
41
39
  this.configService.ensureConfigFileExists();
@@ -43,7 +41,7 @@ class StrategyService {
43
41
  const sourceTrimmed = input.source.trim();
44
42
  const isPinnedNpm = (() => {
45
43
  try {
46
- (0, parse_pinned_spec_1.parsePinnedSpec)(sourceTrimmed);
44
+ parsePinnedSpec(sourceTrimmed);
47
45
  return true;
48
46
  }
49
47
  catch {
@@ -53,29 +51,29 @@ class StrategyService {
53
51
  if (isPinnedNpm) {
54
52
  const pinned = this.packStore.installPinned(sourceTrimmed);
55
53
  const packRoot = this.packStore.resolvePackRoot(pinned.name);
56
- const strategies = (0, strategy_pack_read_1.readStrategiesFromPackRoot)(packRoot);
54
+ const strategies = readStrategiesFromPackRoot(packRoot);
57
55
  if (strategies.length === 0) {
58
56
  throw new Error(`No *.strategy.json found in package: ${pinned.spec}`);
59
57
  }
60
- const allUnits = strategies.flatMap((s) => (0, strategy_normalize_1.normalizeStrategyUnits)(s));
61
- const refs = (0, strategy_analyze_1.uniq)(allUnits.map((u) => u.ref));
62
- (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(this.unitStore.readInstalledDependencyVersions(), refs);
58
+ const allUnits = strategies.flatMap((s) => normalizeStrategyUnits(s));
59
+ const refs = uniq(allUnits.map((u) => u.ref));
60
+ ensureNoInstalledVersionConflicts(this.unitStore.readInstalledDependencyVersions(), refs);
63
61
  refs.forEach((ref) => this.unitStore.installPinned(ref));
64
62
  const installedStrategies = [];
65
63
  strategies.forEach((strategy) => {
66
64
  const name = strategy.name;
67
65
  const strategyPath = this.getStrategyPath(name);
68
- if (!input.force && node_fs_1.default.existsSync(strategyPath)) {
66
+ if (!input.force && fs.existsSync(strategyPath)) {
69
67
  return;
70
68
  }
71
69
  const toWrite = {
72
70
  ...strategy,
73
71
  source: { type: "npm", value: pinned.spec }
74
72
  };
75
- (0, strategy_io_1.writeJsonAtomic)(strategyPath, toWrite);
73
+ writeJsonAtomic(strategyPath, toWrite);
76
74
  installedStrategies.push(name);
77
75
  });
78
- const nextConfig = installedStrategies.reduce((acc, s) => (0, strategy_config_1.withStrategyInConfig)(acc, s), config);
76
+ const nextConfig = installedStrategies.reduce((acc, s) => withStrategyInConfig(acc, s), config);
79
77
  const existing = nextConfig.strategyPacks ?? [];
80
78
  const filtered = existing.filter((x) => {
81
79
  if (typeof x === "string") {
@@ -93,60 +91,60 @@ class StrategyService {
93
91
  this.configService.writeConfig({ ...nextConfig, strategyPacks });
94
92
  return { installedRefs: refs, installedStrategies };
95
93
  }
96
- const { strategy, source } = await (0, strategy_fetch_1.fetchStrategyFile)(sourceTrimmed);
97
- const normalizedUnits = (0, strategy_normalize_1.normalizeStrategyUnits)(strategy);
98
- const refs = (0, strategy_analyze_1.uniq)(normalizedUnits.map((u) => u.ref));
94
+ const { strategy, source } = await fetchStrategyFile(sourceTrimmed);
95
+ const normalizedUnits = normalizeStrategyUnits(strategy);
96
+ const refs = uniq(normalizedUnits.map((u) => u.ref));
99
97
  const strategyPath = this.getStrategyPath(strategy.name);
100
- if (!input.force && node_fs_1.default.existsSync(strategyPath)) {
98
+ if (!input.force && fs.existsSync(strategyPath)) {
101
99
  throw new Error(`Strategy already exists: ${strategy.name}`);
102
100
  }
103
- (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(this.unitStore.readInstalledDependencyVersions(), refs);
101
+ ensureNoInstalledVersionConflicts(this.unitStore.readInstalledDependencyVersions(), refs);
104
102
  refs.forEach((ref) => this.unitStore.installPinned(ref));
105
103
  const toWrite = {
106
104
  ...strategy,
107
105
  source
108
106
  };
109
- (0, strategy_io_1.writeJsonAtomic)(strategyPath, toWrite);
110
- this.configService.writeConfig((0, strategy_config_1.withStrategyInConfig)(config, strategy.name));
107
+ writeJsonAtomic(strategyPath, toWrite);
108
+ this.configService.writeConfig(withStrategyInConfig(config, strategy.name));
111
109
  return { installedRefs: refs, installedStrategies: [strategy.name] };
112
110
  }
113
111
  removeStrategy(name) {
114
112
  this.configService.ensureConfigFileExists();
115
113
  const config = this.configService.readConfigOrDefault();
116
- (0, strategy_config_1.requireStrategyInstalled)(config, name);
114
+ requireStrategyInstalled(config, name);
117
115
  const strategyPath = this.getStrategyPath(name);
118
- if (node_fs_1.default.existsSync(strategyPath)) {
119
- node_fs_1.default.rmSync(strategyPath);
116
+ if (fs.existsSync(strategyPath)) {
117
+ fs.rmSync(strategyPath);
120
118
  }
121
- this.configService.writeConfig((0, strategy_config_1.withoutStrategyInConfig)(config, name));
119
+ this.configService.writeConfig(withoutStrategyInConfig(config, name));
122
120
  }
123
121
  async updateStrategy(name, opts) {
124
122
  this.configService.ensureConfigFileExists();
125
123
  const config = this.configService.readConfigOrDefault();
126
- const names = name ? [name] : (0, strategy_config_1.listStrategyNamesFromConfig)(config);
124
+ const names = name ? [name] : listStrategyNamesFromConfig(config);
127
125
  if (names.length === 0) {
128
126
  return;
129
127
  }
130
128
  const installed = this.unitStore.readInstalledDependencyVersions();
131
129
  if (opts?.packageOnly) {
132
- const packageNames = (0, strategy_analyze_1.uniq)(names
133
- .flatMap((n) => (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n)).map((u) => (0, parse_pinned_spec_1.parsePinnedSpec)(u.ref).name))
130
+ const packageNames = uniq(names
131
+ .flatMap((n) => normalizeStrategyUnits(this.readStrategy(n)).map((u) => parsePinnedSpec(u.ref).name))
134
132
  .filter((x) => x.trim().length > 0));
135
133
  packageNames.forEach((pkg) => {
136
134
  this.unitStore.updateToLatest(pkg);
137
135
  });
138
136
  const afterInstalled = this.unitStore.readInstalledDependencyVersions();
139
- const afterStrategies = (0, strategy_config_1.listStrategyNamesFromConfig)(config).map((n) => ({
137
+ const afterStrategies = listStrategyNamesFromConfig(config).map((n) => ({
140
138
  name: n,
141
- units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n))
139
+ units: normalizeStrategyUnits(this.readStrategy(n))
142
140
  }));
143
- const wanted = (0, strategy_analyze_1.collectWantedVersions)(afterStrategies);
144
- const conflicts = (0, strategy_analyze_1.computeConflicts)(wanted);
141
+ const wanted = collectWantedVersions(afterStrategies);
142
+ const conflicts = computeConflicts(wanted);
145
143
  if (conflicts.length > 0) {
146
144
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
147
145
  }
148
146
  const drift = afterStrategies
149
- .map((s) => (0, strategy_analyze_1.computeDrift)({ strategyName: s.name, units: s.units, installed: afterInstalled }))
147
+ .map((s) => computeDrift({ strategyName: s.name, units: s.units, installed: afterInstalled }))
150
148
  .filter((d) => d.items.length > 0);
151
149
  if (drift.length > 0) {
152
150
  throw new Error("Strategy drift detected after --package-only update. Run 'pp strategy doctor'.");
@@ -165,23 +163,23 @@ class StrategyService {
165
163
  npmPacksToUpdate.add(src.value);
166
164
  continue;
167
165
  }
168
- const fetched = await (0, strategy_fetch_1.fetchStrategyFile)(src.value);
166
+ const fetched = await fetchStrategyFile(src.value);
169
167
  if (fetched.strategy.name !== n) {
170
168
  throw new Error(`Strategy name mismatch while updating ${n}: got ${fetched.strategy.name}`);
171
169
  }
172
170
  const file = { ...fetched.strategy, source: fetched.source };
173
- const units = (0, strategy_normalize_1.normalizeStrategyUnits)(file);
171
+ const units = normalizeStrategyUnits(file);
174
172
  nextStrategies.push({ name: n, file, units });
175
173
  }
176
174
  if (npmPacksToUpdate.size > 0) {
177
175
  const specs = [...npmPacksToUpdate];
178
176
  specs.forEach((spec) => {
179
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
177
+ const pinned = parsePinnedSpec(spec);
180
178
  this.packStore.updateToLatest(pinned.name);
181
179
  });
182
180
  const installedPackVersions = this.packStore.readInstalledDependencyVersions();
183
181
  const updatedSpecs = specs.map((spec) => {
184
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
182
+ const pinned = parsePinnedSpec(spec);
185
183
  const v = installedPackVersions[pinned.name];
186
184
  if (!v) {
187
185
  throw new Error(`Strategy pack not installed after update: ${pinned.name}`);
@@ -190,16 +188,16 @@ class StrategyService {
190
188
  });
191
189
  const updatedFiles = [];
192
190
  updatedSpecs.forEach((spec) => {
193
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
191
+ const pinned = parsePinnedSpec(spec);
194
192
  const root = this.packStore.resolvePackRoot(pinned.name);
195
- const files = (0, strategy_pack_read_1.readStrategiesFromPackRoot)(root).map((f) => ({
193
+ const files = readStrategiesFromPackRoot(root).map((f) => ({
196
194
  ...f,
197
195
  source: { type: "npm", value: spec }
198
196
  }));
199
197
  updatedFiles.push(...files);
200
198
  });
201
199
  updatedFiles.forEach((file) => {
202
- const units = (0, strategy_normalize_1.normalizeStrategyUnits)(file);
200
+ const units = normalizeStrategyUnits(file);
203
201
  nextStrategies.push({ name: file.name, file, units });
204
202
  });
205
203
  const nextConfig = this.configService.readConfigOrDefault();
@@ -208,48 +206,48 @@ class StrategyService {
208
206
  if (typeof x === "string") {
209
207
  return x.trim().length > 0;
210
208
  }
211
- return !updatedSpecs.some((spec) => (0, parse_pinned_spec_1.parsePinnedSpec)(spec).name === x.name);
209
+ return !updatedSpecs.some((spec) => parsePinnedSpec(spec).name === x.name);
212
210
  });
213
211
  const packsNext = [
214
212
  ...filtered,
215
213
  ...updatedSpecs.map((spec) => {
216
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(spec);
214
+ const pinned = parsePinnedSpec(spec);
217
215
  return { name: pinned.name, spec: pinned.spec };
218
216
  })
219
217
  ];
220
218
  this.configService.writeConfig({ ...nextConfig, strategyPacks: packsNext });
221
219
  }
222
- const allOtherNames = (0, strategy_config_1.listStrategyNamesFromConfig)(config).filter((n) => !names.includes(n));
220
+ const allOtherNames = listStrategyNamesFromConfig(config).filter((n) => !names.includes(n));
223
221
  const otherStrategies = allOtherNames.map((n) => ({
224
222
  name: n,
225
- units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n))
223
+ units: normalizeStrategyUnits(this.readStrategy(n))
226
224
  }));
227
- const wanted = (0, strategy_analyze_1.collectWantedVersions)([
225
+ const wanted = collectWantedVersions([
228
226
  ...otherStrategies,
229
227
  ...nextStrategies.map((s) => ({ name: s.name, units: s.units }))
230
228
  ]);
231
- const conflicts = (0, strategy_analyze_1.computeConflicts)(wanted);
229
+ const conflicts = computeConflicts(wanted);
232
230
  if (conflicts.length > 0) {
233
231
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
234
232
  }
235
- const refs = (0, strategy_analyze_1.uniq)(nextStrategies.flatMap((s) => s.units.map((u) => u.ref)));
236
- (0, strategy_analyze_1.ensureNoInstalledVersionConflicts)(installed, refs);
233
+ const refs = uniq(nextStrategies.flatMap((s) => s.units.map((u) => u.ref)));
234
+ ensureNoInstalledVersionConflicts(installed, refs);
237
235
  refs.forEach((ref) => {
238
236
  this.unitStore.installPinned(ref);
239
237
  });
240
238
  nextStrategies.forEach((s) => {
241
- (0, strategy_io_1.writeJsonAtomic)(this.getStrategyPath(s.name), s.file);
239
+ writeJsonAtomic(this.getStrategyPath(s.name), s.file);
242
240
  });
243
241
  }
244
242
  pinStrategy(name) {
245
243
  this.configService.ensureConfigFileExists();
246
244
  const config = this.configService.readConfigOrDefault();
247
- (0, strategy_config_1.requireStrategyInstalled)(config, name);
245
+ requireStrategyInstalled(config, name);
248
246
  const file = this.readStrategy(name);
249
- const units = (0, strategy_normalize_1.normalizeStrategyUnits)(file);
247
+ const units = normalizeStrategyUnits(file);
250
248
  const installed = this.unitStore.readInstalledDependencyVersions();
251
249
  const pinnedUnits = units.map((u) => {
252
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(u.ref);
250
+ const pinned = parsePinnedSpec(u.ref);
253
251
  const v = installed[pinned.name];
254
252
  if (!v) {
255
253
  throw new Error(`Unit package is not installed: ${pinned.name}`);
@@ -257,17 +255,17 @@ class StrategyService {
257
255
  const nextRef = `${pinned.name}@${v}`;
258
256
  return u.args.length === 0 ? nextRef : { ref: nextRef, args: u.args };
259
257
  });
260
- const others = (0, strategy_config_1.listStrategyNamesFromConfig)(config)
258
+ const others = listStrategyNamesFromConfig(config)
261
259
  .filter((n) => n !== name)
262
- .map((n) => ({ name: n, units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n)) }));
263
- const nextWanted = (0, strategy_analyze_1.collectWantedVersions)([
260
+ .map((n) => ({ name: n, units: normalizeStrategyUnits(this.readStrategy(n)) }));
261
+ const nextWanted = collectWantedVersions([
264
262
  ...others,
265
263
  {
266
264
  name,
267
265
  units: pinnedUnits.map((x) => typeof x === "string" ? { ref: x, args: [] } : { ref: x.ref, args: x.args ?? [] })
268
266
  }
269
267
  ]);
270
- const conflicts = (0, strategy_analyze_1.computeConflicts)(nextWanted);
268
+ const conflicts = computeConflicts(nextWanted);
271
269
  if (conflicts.length > 0) {
272
270
  throw new Error(`Strategy version conflicts detected (${conflicts.length}). Run 'pp strategy doctor' for details.`);
273
271
  }
@@ -278,23 +276,22 @@ class StrategyService {
278
276
  units: pinnedUnits
279
277
  }
280
278
  };
281
- (0, strategy_io_1.writeJsonAtomic)(this.getStrategyPath(name), nextFile);
279
+ writeJsonAtomic(this.getStrategyPath(name), nextFile);
282
280
  }
283
281
  doctor() {
284
282
  this.configService.ensureConfigFileExists();
285
283
  const config = this.configService.readConfigOrDefault();
286
- const names = (0, strategy_config_1.listStrategyNamesFromConfig)(config);
284
+ const names = listStrategyNamesFromConfig(config);
287
285
  const installed = this.unitStore.readInstalledDependencyVersions();
288
286
  const strategies = names.map((n) => ({
289
287
  name: n,
290
- units: (0, strategy_normalize_1.normalizeStrategyUnits)(this.readStrategy(n))
288
+ units: normalizeStrategyUnits(this.readStrategy(n))
291
289
  }));
292
- const wanted = (0, strategy_analyze_1.collectWantedVersions)(strategies);
293
- const conflicts = (0, strategy_analyze_1.computeConflicts)(wanted);
290
+ const wanted = collectWantedVersions(strategies);
291
+ const conflicts = computeConflicts(wanted);
294
292
  const drift = strategies
295
- .map((s) => (0, strategy_analyze_1.computeDrift)({ strategyName: s.name, units: s.units, installed }))
293
+ .map((s) => computeDrift({ strategyName: s.name, units: s.units, installed }))
296
294
  .filter((d) => d.items.length > 0);
297
295
  return { conflicts, drift };
298
296
  }
299
297
  }
300
- exports.StrategyService = StrategyService;
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -1,15 +1,13 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnitStore = void 0;
4
- const user_package_installer_1 = require("../user-packages/user-package-installer");
5
- const parse_pinned_spec_1 = require("../user-packages/parse-pinned-spec");
6
- const user_package_store_1 = require("../user-packages/user-package-store");
7
- const unit_validate_1 = require("./unit-validate");
1
+ import { installPinnedPackage, updatePackageToLatest } from "../user-packages/user-package-installer.js";
2
+ import { parsePinnedSpec } from "../user-packages/parse-pinned-spec.js";
3
+ import { UserPackageStore } from "../user-packages/user-package-store.js";
4
+ import { isUnitLike, resolveUnitConstructor } from "./unit-validate.js";
8
5
  const UNITS_KIND = "units";
9
6
  const UNITS_PACKAGE_JSON_NAME = "pagepocket-user-units";
10
- class UnitStore {
7
+ export class UnitStore {
8
+ store;
11
9
  constructor(configService) {
12
- this.store = new user_package_store_1.UserPackageStore(configService, UNITS_KIND);
10
+ this.store = new UserPackageStore(configService, UNITS_KIND);
13
11
  }
14
12
  getInstallDir() {
15
13
  return this.store.getInstallDir();
@@ -21,14 +19,14 @@ class UnitStore {
21
19
  return this.store.readInstalledPackageMeta(UNITS_PACKAGE_JSON_NAME, packageName);
22
20
  }
23
21
  installPinned(ref) {
24
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(ref);
25
- (0, user_package_installer_1.installPinnedPackage)(this.store, {
22
+ const pinned = parsePinnedSpec(ref);
23
+ installPinnedPackage(this.store, {
26
24
  packageJsonName: UNITS_PACKAGE_JSON_NAME,
27
25
  packageSpec: pinned.spec
28
26
  });
29
27
  }
30
28
  updateToLatest(packageName) {
31
- (0, user_package_installer_1.updatePackageToLatest)(this.store, {
29
+ updatePackageToLatest(this.store, {
32
30
  packageJsonName: UNITS_PACKAGE_JSON_NAME,
33
31
  packageName
34
32
  });
@@ -37,18 +35,16 @@ class UnitStore {
37
35
  return this.store.importModule(UNITS_PACKAGE_JSON_NAME, packageName);
38
36
  }
39
37
  async instantiateFromRef(ref, args) {
40
- const pinned = (0, parse_pinned_spec_1.parsePinnedSpec)(ref);
38
+ const pinned = parsePinnedSpec(ref);
41
39
  const mod = await this.importUnitModule(pinned.name);
42
- const def = mod.default;
43
- if (typeof def !== "function") {
44
- throw new Error(`Unit ${pinned.name} must default export a constructor.`);
40
+ const ctor = resolveUnitConstructor(mod);
41
+ if (!ctor) {
42
+ throw new Error(`Unit ${pinned.name} does not export a Unit constructor.`);
45
43
  }
46
- const ctor = def;
47
44
  const instance = new ctor(...args);
48
- if (!(0, unit_validate_1.isUnitLike)(instance)) {
49
- throw new Error(`Unit ${pinned.name} default export did not construct a Unit.`);
45
+ if (!isUnitLike(instance)) {
46
+ throw new Error(`Unit ${pinned.name} exported constructor did not produce a Unit.`);
50
47
  }
51
48
  return instance;
52
49
  }
53
50
  }
54
- exports.UnitStore = UnitStore;
@@ -1,13 +1,10 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isUnitLike = void 0;
4
1
  const isRecord = (value) => {
5
2
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6
3
  };
7
4
  const isCallable = (value) => {
8
5
  return typeof value === "function";
9
6
  };
10
- const isUnitLike = (value) => {
7
+ export const isUnitLike = (value) => {
11
8
  if (!isRecord(value)) {
12
9
  return false;
13
10
  }
@@ -25,4 +22,22 @@ const isUnitLike = (value) => {
25
22
  }
26
23
  return true;
27
24
  };
28
- exports.isUnitLike = isUnitLike;
25
+ /**
26
+ * Resolve a Unit constructor from an imported ESM module.
27
+ *
28
+ * Checks `mod.default` first. If it is not a function (e.g. older packages
29
+ * that only use named exports), falls back to the first exported function
30
+ * whose name ends with "Unit".
31
+ *
32
+ * @returns The constructor function, or `undefined` when none is found.
33
+ */
34
+ export const resolveUnitConstructor = (mod) => {
35
+ if (typeof mod.default === "function") {
36
+ return mod.default;
37
+ }
38
+ const fallback = Object.values(mod).find((v) => typeof v === "function" && v.name?.endsWith("Unit"));
39
+ if (typeof fallback === "function") {
40
+ return fallback;
41
+ }
42
+ return undefined;
43
+ };
@@ -1,18 +1,19 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parsePinnedSpec = void 0;
1
+ import path from "node:path";
2
+ import { createRequire } from "node:module";
3
+ import { fileURLToPath } from "node:url";
4
4
  const isRecord = (value) => {
5
5
  return Boolean(value) && typeof value === "object" && !Array.isArray(value);
6
6
  };
7
7
  const isExactSemver = (value) => {
8
8
  return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(value);
9
9
  };
10
- const parsePinnedSpec = (input) => {
10
+ export const parsePinnedSpec = (input) => {
11
11
  const trimmed = input.trim();
12
12
  if (!trimmed) {
13
13
  throw new Error("package spec is empty");
14
14
  }
15
- const npa = require("npm-package-arg");
15
+ const req = createRequire(import.meta.url ? fileURLToPath(import.meta.url) : path.join(process.cwd(), "package.json"));
16
+ const npa = req("npm-package-arg");
16
17
  const parsed = npa(trimmed);
17
18
  if (!isRecord(parsed)) {
18
19
  throw new Error(`Invalid package spec: ${trimmed}`);
@@ -34,4 +35,3 @@ const parsePinnedSpec = (input) => {
34
35
  }
35
36
  return { name, version: rawSpec, spec: `${name}@${rawSpec}` };
36
37
  };
37
- exports.parsePinnedSpec = parsePinnedSpec;