@loopress/cli 0.23.0 → 0.24.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/README.md +603 -94
- package/dist/commands/acf/diff.d.ts +2 -0
- package/dist/commands/acf/diff.js +5 -0
- package/dist/commands/api/diff.d.ts +2 -0
- package/dist/commands/api/diff.js +5 -0
- package/dist/commands/api/list.d.ts +2 -12
- package/dist/commands/api/list.js +2 -20
- package/dist/commands/api/pull.d.ts +2 -20
- package/dist/commands/api/pull.js +2 -53
- package/dist/commands/api/push.d.ts +2 -22
- package/dist/commands/api/push.js +2 -116
- package/dist/commands/api/rm.d.ts +2 -0
- package/dist/commands/api/rm.js +2 -0
- package/dist/commands/composer/pull.js +6 -16
- package/dist/commands/composer/push.d.ts +3 -0
- package/dist/commands/composer/push.js +24 -7
- package/dist/commands/dev.js +1 -1
- package/dist/commands/diff.d.ts +13 -0
- package/dist/commands/diff.js +42 -0
- package/dist/commands/form/diff.d.ts +2 -0
- package/dist/commands/form/diff.js +5 -0
- package/dist/commands/form/push.d.ts +2 -0
- package/dist/commands/form/push.js +11 -4
- package/dist/commands/hook/diff.d.ts +2 -0
- package/dist/commands/hook/diff.js +5 -0
- package/dist/commands/hook/list.d.ts +2 -0
- package/dist/commands/hook/list.js +2 -0
- package/dist/commands/hook/pull.d.ts +2 -0
- package/dist/commands/hook/pull.js +2 -0
- package/dist/commands/hook/push.d.ts +2 -0
- package/dist/commands/hook/push.js +2 -0
- package/dist/commands/hook/rm.d.ts +2 -0
- package/dist/commands/hook/rm.js +2 -0
- package/dist/commands/init.js +1 -1
- package/dist/commands/login.js +3 -2
- package/dist/commands/option/add.d.ts +15 -0
- package/dist/commands/option/add.js +47 -0
- package/dist/commands/option/diff.d.ts +2 -0
- package/dist/commands/option/diff.js +5 -0
- package/dist/commands/{page → option}/list.d.ts +5 -1
- package/dist/commands/option/list.js +151 -0
- package/dist/commands/{page → option}/pull.d.ts +3 -12
- package/dist/commands/option/pull.js +75 -0
- package/dist/commands/{page → option}/push.d.ts +3 -8
- package/dist/commands/option/push.js +66 -0
- package/dist/commands/option/remove.d.ts +22 -0
- package/dist/commands/option/remove.js +69 -0
- package/dist/commands/plugin/push.d.ts +0 -1
- package/dist/commands/plugin/push.js +3 -10
- package/dist/commands/pull.js +3 -2
- package/dist/commands/push.js +4 -3
- package/dist/commands/seo/diff.d.ts +2 -0
- package/dist/commands/seo/diff.js +5 -0
- package/dist/commands/seo/push.d.ts +2 -0
- package/dist/commands/seo/push.js +16 -4
- package/dist/commands/snippet/diff.d.ts +2 -0
- package/dist/commands/snippet/diff.js +5 -0
- package/dist/commands/theme/push.d.ts +0 -1
- package/dist/commands/theme/push.js +3 -10
- package/dist/hooks/finally.js +4 -1
- package/dist/lib/base.d.ts +2 -1
- package/dist/lib/base.js +12 -22
- package/dist/lib/dev-watch.d.ts +1 -1
- package/dist/lib/dev-watch.js +1 -2
- package/dist/lib/diff-command.d.ts +47 -0
- package/dist/lib/diff-command.js +180 -0
- package/dist/lib/diff-state.d.ts +22 -0
- package/dist/lib/diff-state.js +88 -0
- package/dist/lib/find-orphaned-files.js +1 -1
- package/dist/lib/interactive.d.ts +1 -0
- package/dist/lib/interactive.js +10 -0
- package/dist/lib/local-callback-server.d.ts +14 -1
- package/dist/lib/local-callback-server.js +40 -1
- package/dist/lib/php-files-command.d.ts +67 -0
- package/dist/lib/php-files-command.js +338 -0
- package/dist/lib/put-or-create.js +1 -1
- package/dist/lib/readdir-tolerant.d.ts +1 -0
- package/dist/lib/readdir-tolerant.js +3 -1
- package/dist/lib/resource-state.d.ts +14 -0
- package/dist/lib/resource-state.js +361 -0
- package/dist/lib/sentry.d.ts +3 -0
- package/dist/lib/sentry.js +30 -0
- package/dist/lib/validate-local.js +15 -7
- package/dist/lib/wp-authorize-flow.d.ts +4 -0
- package/dist/lib/wp-authorize-flow.js +10 -8
- package/dist/lib/wp-client.d.ts +5 -0
- package/dist/lib/wp-client.js +56 -0
- package/dist/types/project-config.generated.d.ts +8 -4
- package/dist/utils/option-format.d.ts +31 -0
- package/dist/utils/option-format.js +69 -0
- package/dist/utils/plugin-sync.d.ts +6 -0
- package/dist/utils/resource-dirs.d.ts +13 -0
- package/dist/utils/resource-dirs.js +34 -0
- package/oclif.manifest.json +1488 -301
- package/package.json +11 -8
- package/schemas/project-config.schema.json +10 -5
- package/dist/commands/page/list.js +0 -19
- package/dist/commands/page/pull.js +0 -57
- package/dist/commands/page/push.js +0 -132
- package/dist/utils/page-format.d.ts +0 -7
- package/dist/utils/page-format.js +0 -78
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export const OPTIONS_ENDPOINT = 'loopress/v1/options';
|
|
2
|
+
export function optionEndpoint(name) {
|
|
3
|
+
return `${OPTIONS_ENDPOINT}/${encodeURIComponent(name)}`;
|
|
4
|
+
}
|
|
5
|
+
// Mirrors OptionsService::RESERVED_NAMES on the WordPress side (the actual, unbypassable
|
|
6
|
+
// enforcement lives there). Checked here too so `option add` fails fast with a clear pointer to
|
|
7
|
+
// the right command, instead of a round trip just to hit the server's 409.
|
|
8
|
+
export const RESERVED_OPTION_NAMES = ['active_plugins', 'stylesheet', 'template'];
|
|
9
|
+
// Options WordPress core owns or regenerates itself, plus the ones OptionsService::
|
|
10
|
+
// DENY_WRITE_NAMES refuses server-side (behaviour-changing core options: default_role,
|
|
11
|
+
// users_can_register, mailserver_*, ...). Legitimate to track for visibility (`diff` still
|
|
12
|
+
// shows drift), but never something `push` should overwrite by default. siteurl/home in
|
|
13
|
+
// particular: pushing a value copied from another environment would repoint the target site's
|
|
14
|
+
// own URLs, potentially locking out wp-admin. Flip `readonly` in the file to push one anyway;
|
|
15
|
+
// for the server-denied names that then needs the `loopress_option_writable` filter too.
|
|
16
|
+
export const READONLY_BY_DEFAULT_OPTION_NAMES = [
|
|
17
|
+
'siteurl',
|
|
18
|
+
'home',
|
|
19
|
+
'db_version',
|
|
20
|
+
'initial_db_version',
|
|
21
|
+
'cron',
|
|
22
|
+
'rewrite_rules',
|
|
23
|
+
'WPLANG',
|
|
24
|
+
'default_role',
|
|
25
|
+
'users_can_register',
|
|
26
|
+
'uninstall_plugins',
|
|
27
|
+
'mailserver_url',
|
|
28
|
+
'mailserver_login',
|
|
29
|
+
'mailserver_pass',
|
|
30
|
+
'mailserver_port',
|
|
31
|
+
];
|
|
32
|
+
export function isReservedOptionName(name) {
|
|
33
|
+
return RESERVED_OPTION_NAMES.includes(name);
|
|
34
|
+
}
|
|
35
|
+
export function defaultReadonlyFor(name) {
|
|
36
|
+
return READONLY_BY_DEFAULT_OPTION_NAMES.includes(name);
|
|
37
|
+
}
|
|
38
|
+
export function optionFileName(name) {
|
|
39
|
+
return `${name}.json`;
|
|
40
|
+
}
|
|
41
|
+
// Splits tracked options into what `push` may write and what it must skip: readonly is a local
|
|
42
|
+
// policy flag (see READONLY_BY_DEFAULT_OPTION_NAMES), never something WordPress itself enforces.
|
|
43
|
+
export function partitionByReadonly(tracked) {
|
|
44
|
+
const writable = [];
|
|
45
|
+
const skipped = [];
|
|
46
|
+
for (const option of tracked)
|
|
47
|
+
(option.readonly ? skipped : writable).push(option);
|
|
48
|
+
return { skipped, writable };
|
|
49
|
+
}
|
|
50
|
+
export function parseLocalOption(raw) {
|
|
51
|
+
const parsed = JSON.parse(raw);
|
|
52
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
53
|
+
throw new Error('not a JSON object');
|
|
54
|
+
}
|
|
55
|
+
const { autoload, name, value } = parsed;
|
|
56
|
+
if (typeof name !== 'string' || name === '') {
|
|
57
|
+
throw new Error('missing a "name" string');
|
|
58
|
+
}
|
|
59
|
+
if (typeof autoload !== 'string') {
|
|
60
|
+
throw new TypeError('missing an "autoload" string');
|
|
61
|
+
}
|
|
62
|
+
// `value` itself is deliberately untyped (a WP option can hold any JSON-safe value, including
|
|
63
|
+
// null); only the key's presence is checked, so a hand-edited file that dropped it entirely is
|
|
64
|
+
// rejected here rather than silently pushing an `undefined` value to WordPress.
|
|
65
|
+
if (value === undefined) {
|
|
66
|
+
throw new Error('missing a "value" field');
|
|
67
|
+
}
|
|
68
|
+
return parsed;
|
|
69
|
+
}
|
|
@@ -9,9 +9,15 @@ export type SyncPayload = {
|
|
|
9
9
|
intent: SyncIntent;
|
|
10
10
|
lock: null | string;
|
|
11
11
|
};
|
|
12
|
+
export type LockDriftEntry = {
|
|
13
|
+
from: null | string;
|
|
14
|
+
name: string;
|
|
15
|
+
to: null | string;
|
|
16
|
+
};
|
|
12
17
|
export type SyncResponse = {
|
|
13
18
|
composerJson: string;
|
|
14
19
|
composerLock: string;
|
|
20
|
+
lockDrift?: LockDriftEntry[];
|
|
15
21
|
message: string;
|
|
16
22
|
output: string;
|
|
17
23
|
removed: string[];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type LoopressLocalConfig } from './loopress-config.js';
|
|
2
|
+
export declare const RESOURCE_DIR_DEFAULTS: {
|
|
3
|
+
readonly acf: "acf";
|
|
4
|
+
readonly api: "api";
|
|
5
|
+
readonly apps: "apps";
|
|
6
|
+
readonly form: "forms";
|
|
7
|
+
readonly hooks: "hooks";
|
|
8
|
+
readonly options: "options";
|
|
9
|
+
readonly seo: "seo";
|
|
10
|
+
readonly snippets: "snippets";
|
|
11
|
+
};
|
|
12
|
+
export type ResourceDirKind = keyof typeof RESOURCE_DIR_DEFAULTS;
|
|
13
|
+
export declare function resolveResourceDir(kind: ResourceDirKind, localConfig: LoopressLocalConfig, override?: string): string;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
// The default subdirectory for each file-backed resource, relative to rootDir. `lps init`
|
|
3
|
+
// writes these same defaults into loopress.json, keep the two in sync.
|
|
4
|
+
export const RESOURCE_DIR_DEFAULTS = {
|
|
5
|
+
acf: 'acf',
|
|
6
|
+
api: 'api',
|
|
7
|
+
apps: 'apps',
|
|
8
|
+
form: 'forms',
|
|
9
|
+
hooks: 'hooks',
|
|
10
|
+
options: 'options',
|
|
11
|
+
seo: 'seo',
|
|
12
|
+
snippets: 'snippets',
|
|
13
|
+
};
|
|
14
|
+
const CONFIG_KEY = {
|
|
15
|
+
acf: 'acfDir',
|
|
16
|
+
api: 'apiDir',
|
|
17
|
+
apps: 'appsDir',
|
|
18
|
+
form: 'formDir',
|
|
19
|
+
hooks: 'hooksDir',
|
|
20
|
+
options: 'optionsDir',
|
|
21
|
+
seo: 'seoDir',
|
|
22
|
+
snippets: 'snippetsDir',
|
|
23
|
+
};
|
|
24
|
+
// Resolves where a resource's files live: an explicit override wins, otherwise the
|
|
25
|
+
// loopress.json `<kind>Dir` setting, otherwise the built-in default, all under `rootDir`.
|
|
26
|
+
// Shared by every pull/push command (via LoopressCommand's resolve*Path helpers) and by
|
|
27
|
+
// `lps diff`, so the resolution rule has a single home.
|
|
28
|
+
export function resolveResourceDir(kind, localConfig, override) {
|
|
29
|
+
if (override)
|
|
30
|
+
return override;
|
|
31
|
+
const rootDir = localConfig.rootDir ?? '.';
|
|
32
|
+
const configured = localConfig[CONFIG_KEY[kind]];
|
|
33
|
+
return join(rootDir, configured ?? RESOURCE_DIR_DEFAULTS[kind]);
|
|
34
|
+
}
|