@webikon/webentor-codemods 0.1.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/CHANGELOG.md +24 -0
- package/LICENCE.md +7 -0
- package/README.md +85 -0
- package/bin/webentor-codemods.mjs +215 -0
- package/migrations/0.13.0/README.md +99 -0
- package/migrations/0.13.0/rules/deps.yml +311 -0
- package/migrations/0.13.0/rules/editor-enqueue-iframe.yml +62 -0
- package/migrations/__fixtures__/0.13.0/after/app/setup.php +226 -0
- package/migrations/__fixtures__/0.13.0/after/composer.json +63 -0
- package/migrations/__fixtures__/0.13.0/after/package.json +86 -0
- package/migrations/__fixtures__/0.13.0/before/app/setup.php +211 -0
- package/migrations/__fixtures__/0.13.0/before/composer.json +63 -0
- package/migrations/__fixtures__/0.13.0/before/package.json +86 -0
- package/migrations/__fixtures__/0.13.0/customized/app/setup.php +24 -0
- package/migrations/__fixtures__/0.13.0/customized/composer.json +63 -0
- package/migrations/__fixtures__/0.13.0/customized/package.json +86 -0
- package/migrations/index.json +17 -0
- package/package.json +52 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Webentor Codemods Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Initial release of `@webikon/webentor-codemods` — a reusable, ast-grep–powered
|
|
6
|
+
codemod runner for migrating consumer theme code across `webentor-core` updates.
|
|
7
|
+
- CLI: `list`, `run <id>`, and `run --since <ver> [--to <ver>]` (dry-run by
|
|
8
|
+
default, `--apply` to write).
|
|
9
|
+
- Migrations are **named by the webentor-core version** they upgrade to — the id
|
|
10
|
+
*is* the target version, so `run 0.13.0` reads as "run the 0.13.0 codemod".
|
|
11
|
+
- First migration `0.13.0` (core 0.12 → 0.13), with two rule sets:
|
|
12
|
+
- `editor-enqueue-iframe.yml` (PHP): moves the theme's `editor.css` +
|
|
13
|
+
`button.style.css` enqueues from `enqueue_block_editor_assets` to a new
|
|
14
|
+
`enqueue_block_assets` hook (`is_admin()` guarded) for WP 7.0's iframed
|
|
15
|
+
editor; the editor JS stays put.
|
|
16
|
+
- `deps.yml` (JSON, multi-rule): rewrites the theme's `package.json` +
|
|
17
|
+
`composer.json` dependency ranges to the 0.13.0 baseline — `webentor-core`
|
|
18
|
+
`^0.13` plus the full aligned third-party set (incl. major bumps
|
|
19
|
+
`@wordpress/components` 30→35, `@wordpress/icons` 11→14, `stylelint` 16→17,
|
|
20
|
+
`@types/wordpress__block-editor` 14→15). Value-is-string guarded so config
|
|
21
|
+
objects sharing a key aren't touched; `name`/`version` untouched.
|
|
22
|
+
- Polyglot golden tests run a migration's rules over a `before/` fixture subtree
|
|
23
|
+
(PHP + JSON together) and assert byte-exact equality with `after/`, plus
|
|
24
|
+
idempotency and a safe no-op on customized/already-migrated trees.
|
package/LICENCE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Copyright (c) Webikon s.r.o.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
+
|
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
+
|
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# @webikon/webentor-codemods
|
|
2
|
+
|
|
3
|
+
Reusable, polyglot **codemods** for migrating Webentor Stack consumer projects
|
|
4
|
+
across `webentor-core` updates. When a core release requires a mechanical change
|
|
5
|
+
to **consumer-owned theme code** (PHP / TS / CSS / JSON), the fix ships here as a
|
|
6
|
+
versioned migration you can run with one command — no install required.
|
|
7
|
+
|
|
8
|
+
Powered by [ast-grep](https://ast-grep.github.io) (AST-based, so it tolerates
|
|
9
|
+
formatting differences a regex would choke on).
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
Run from your **project root** (the directory containing `web/app/themes/…`):
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
# See what's available
|
|
17
|
+
pnpm dlx @webikon/webentor-codemods list
|
|
18
|
+
|
|
19
|
+
# Preview the codemod for a core version (dry-run — prints a diff, writes nothing)
|
|
20
|
+
pnpm dlx @webikon/webentor-codemods run 0.13.0
|
|
21
|
+
|
|
22
|
+
# Apply it
|
|
23
|
+
pnpm dlx @webikon/webentor-codemods run 0.13.0 --apply
|
|
24
|
+
|
|
25
|
+
# Or run every migration across a core version range at once
|
|
26
|
+
pnpm dlx @webikon/webentor-codemods run --since 0.12.0 --to 0.13.0 --apply
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`--path <dir>` targets a different directory (defaults to the current one).
|
|
30
|
+
`--package <name>` narrows `--since` to a package (defaults to `webentor-core`).
|
|
31
|
+
|
|
32
|
+
> Use `npx` instead of `pnpm dlx` if you prefer — both download-and-run without
|
|
33
|
+
> a permanent install.
|
|
34
|
+
|
|
35
|
+
Always run a dry-run first, review the diff, then re-run with `--apply`. After
|
|
36
|
+
applying, rebuild the theme and clear caches (`wp acorn optimize:clear`).
|
|
37
|
+
|
|
38
|
+
## Available migrations
|
|
39
|
+
|
|
40
|
+
Migrations are **named by the webentor-core version** they bring you to — the id
|
|
41
|
+
*is* the target version, so "run the 0.13.0 codemod" reads literally.
|
|
42
|
+
|
|
43
|
+
| id | core | what |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| `0.13.0` | 0.12 → 0.13 | WP 7.0 iframe editor-asset enqueue change (`app/setup.php`) + the full dependency bump set (`package.json` + `composer.json`) |
|
|
46
|
+
|
|
47
|
+
See each migration's `migrations/<id>/README.md` for before/after detail.
|
|
48
|
+
|
|
49
|
+
## How it's built
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
migrations/
|
|
53
|
+
index.json registry (id = version, title, appliesTo range, rule files)
|
|
54
|
+
<version>/ e.g. 0.13.0
|
|
55
|
+
rules/*.yml ast-grep rewrite rule(s), applied in order; one .yml
|
|
56
|
+
may hold several rules as `---`-separated documents
|
|
57
|
+
README.md what/why + before→after
|
|
58
|
+
__fixtures__/<version>/
|
|
59
|
+
before/ after/ golden project subtrees (drive the tests); each holds
|
|
60
|
+
the files a rule touches, e.g. app/setup.php,
|
|
61
|
+
package.json, composer.json
|
|
62
|
+
customized/ (optional) a subtree that must NOT change (no-op guard)
|
|
63
|
+
bin/webentor-codemods.mjs the CLI runner (wraps the bundled ast-grep)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Adding a future migration
|
|
67
|
+
|
|
68
|
+
1. Create `migrations/<version>/rules/<rule>.yml` ast-grep rule(s) with a `fix`.
|
|
69
|
+
Rules can target multiple languages (PHP, JSON, …) — ast-grep dispatches each
|
|
70
|
+
rule to the files matching its `language`. JSON dependency rules use
|
|
71
|
+
`files:` globs to scope to `package.json` / `composer.json`.
|
|
72
|
+
2. Add `before/` + `after/` (and optional `customized/`) fixture subtrees under
|
|
73
|
+
`migrations/__fixtures__/<version>/`.
|
|
74
|
+
3. Register it in `migrations/index.json` (`id` = the version, `appliesTo`, `rules`).
|
|
75
|
+
|
|
76
|
+
The runner and the test suite are generic — no code changes needed. Migrations
|
|
77
|
+
are **idempotent** (re-running is a no-op) and **conservative** (anything that
|
|
78
|
+
doesn't match the targeted shape is left untouched).
|
|
79
|
+
|
|
80
|
+
## Develop & test
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
pnpm install # pulls the ast-grep engine
|
|
84
|
+
pnpm test # golden tests: before→after byte-match, idempotency, no-op safety
|
|
85
|
+
```
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @webikon/webentor-codemods — reusable codemod runner for Webentor Stack
|
|
4
|
+
* consumer projects.
|
|
5
|
+
*
|
|
6
|
+
* A thin wrapper around the bundled `ast-grep` engine (via the `@ast-grep/cli`
|
|
7
|
+
* dependency). Codemods live in `migrations/<id>/rules/*.yml` and are registered
|
|
8
|
+
* in `migrations/index.json`. The runner is intentionally generic: adding a new
|
|
9
|
+
* migration is just a new folder + an index entry — no runner changes needed.
|
|
10
|
+
*
|
|
11
|
+
* Usage (run from your project root):
|
|
12
|
+
* webentor-codemods list
|
|
13
|
+
* webentor-codemods run <id> [--path <dir>] [--apply]
|
|
14
|
+
* webentor-codemods run --since <ver> [--to <ver>] [--package <name>] [--path <dir>] [--apply]
|
|
15
|
+
*
|
|
16
|
+
* Dry-run by default (prints the diff). Pass --apply to write changes.
|
|
17
|
+
*/
|
|
18
|
+
import { createRequire } from 'node:module';
|
|
19
|
+
import { spawnSync } from 'node:child_process';
|
|
20
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
21
|
+
import { dirname, join, resolve } from 'node:path';
|
|
22
|
+
import { fileURLToPath } from 'node:url';
|
|
23
|
+
|
|
24
|
+
const require = createRequire(import.meta.url);
|
|
25
|
+
const PKG_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
26
|
+
const MIGRATIONS_DIR = join(PKG_ROOT, 'migrations');
|
|
27
|
+
|
|
28
|
+
function fail(msg) {
|
|
29
|
+
console.error(`webentor-codemods: ${msg}`);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Resolve the bundled ast-grep binary shipped via @ast-grep/cli. */
|
|
34
|
+
function astGrepBin() {
|
|
35
|
+
try {
|
|
36
|
+
const pkgJson = require.resolve('@ast-grep/cli/package.json');
|
|
37
|
+
const bin = join(dirname(pkgJson), 'ast-grep');
|
|
38
|
+
if (existsSync(bin)) return bin;
|
|
39
|
+
} catch {
|
|
40
|
+
/* fall through to PATH */
|
|
41
|
+
}
|
|
42
|
+
return 'ast-grep'; // last resort: rely on PATH
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function loadRegistry() {
|
|
46
|
+
const indexPath = join(MIGRATIONS_DIR, 'index.json');
|
|
47
|
+
if (!existsSync(indexPath)) fail(`migrations registry not found at ${indexPath}`);
|
|
48
|
+
try {
|
|
49
|
+
return JSON.parse(readFileSync(indexPath, 'utf8'));
|
|
50
|
+
} catch (e) {
|
|
51
|
+
fail(`could not parse migrations/index.json: ${e.message}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Parse a loose "x.y.z" semver into a comparable tuple. Missing parts -> 0. */
|
|
56
|
+
function parseVer(v) {
|
|
57
|
+
const parts = String(v ?? '0')
|
|
58
|
+
.replace(/^[^\d]*/, '')
|
|
59
|
+
.split('.')
|
|
60
|
+
.map((n) => parseInt(n, 10) || 0);
|
|
61
|
+
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function cmpVer(a, b) {
|
|
65
|
+
const x = parseVer(a);
|
|
66
|
+
const y = parseVer(b);
|
|
67
|
+
for (let i = 0; i < 3; i++) {
|
|
68
|
+
if (x[i] !== y[i]) return x[i] - y[i];
|
|
69
|
+
}
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function parseArgs(argv) {
|
|
74
|
+
const positional = [];
|
|
75
|
+
const flags = {};
|
|
76
|
+
for (let i = 0; i < argv.length; i++) {
|
|
77
|
+
const a = argv[i];
|
|
78
|
+
if (a.startsWith('--')) {
|
|
79
|
+
const key = a.slice(2);
|
|
80
|
+
const next = argv[i + 1];
|
|
81
|
+
if (next === undefined || next.startsWith('--')) {
|
|
82
|
+
flags[key] = true;
|
|
83
|
+
} else {
|
|
84
|
+
flags[key] = next;
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
positional.push(a);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return { positional, flags };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function printList(registry) {
|
|
95
|
+
const migrations = registry.migrations ?? [];
|
|
96
|
+
if (!migrations.length) {
|
|
97
|
+
console.log('No migrations registered.');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
console.log('Available migrations:\n');
|
|
101
|
+
for (const m of migrations) {
|
|
102
|
+
const at = m.appliesTo
|
|
103
|
+
? ` (${m.appliesTo.package} ${m.appliesTo.from} → ${m.appliesTo.to})`
|
|
104
|
+
: '';
|
|
105
|
+
console.log(` ${m.id}${at}`);
|
|
106
|
+
if (m.title) console.log(` ${m.title}`);
|
|
107
|
+
if (m.description) console.log(` ${m.description}`);
|
|
108
|
+
console.log('');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Run a single migration's rules (in declared order) against targetPath. */
|
|
113
|
+
function runMigration(migration, { targetPath, apply }) {
|
|
114
|
+
const bin = astGrepBin();
|
|
115
|
+
const migDir = join(MIGRATIONS_DIR, migration.id);
|
|
116
|
+
const rules = migration.rules ?? [];
|
|
117
|
+
if (!rules.length) fail(`migration "${migration.id}" declares no rules`);
|
|
118
|
+
|
|
119
|
+
console.log(
|
|
120
|
+
`\n▶ ${migration.id}${apply ? ' (apply)' : ' (dry-run — pass --apply to write)'}`,
|
|
121
|
+
);
|
|
122
|
+
let anyError = false;
|
|
123
|
+
for (const rel of rules) {
|
|
124
|
+
const rulePath = join(migDir, rel);
|
|
125
|
+
if (!existsSync(rulePath)) fail(`rule file not found: ${rulePath}`);
|
|
126
|
+
const args = ['scan', '--rule', rulePath];
|
|
127
|
+
if (apply) args.push('--update-all');
|
|
128
|
+
args.push(targetPath);
|
|
129
|
+
const res = spawnSync(bin, args, { stdio: 'inherit' });
|
|
130
|
+
if (res.error) {
|
|
131
|
+
console.error(` failed to run ast-grep: ${res.error.message}`);
|
|
132
|
+
anyError = true;
|
|
133
|
+
} else if (res.status !== 0) {
|
|
134
|
+
anyError = true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return !anyError;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function resolveMigrationsToRun(registry, flags, positional) {
|
|
141
|
+
const migrations = registry.migrations ?? [];
|
|
142
|
+
|
|
143
|
+
// `run --since <ver> [--to <ver>] [--package <name>]`
|
|
144
|
+
if (flags.since) {
|
|
145
|
+
const pkg = flags.package || 'webentor-core';
|
|
146
|
+
const from = flags.since;
|
|
147
|
+
const to = flags.to || '999.999.999';
|
|
148
|
+
const selected = migrations.filter((m) => {
|
|
149
|
+
if (!m.appliesTo || m.appliesTo.package !== pkg) return false;
|
|
150
|
+
// Apply migrations whose target ("to") version is in (from, to].
|
|
151
|
+
return cmpVer(m.appliesTo.to, from) > 0 && cmpVer(m.appliesTo.to, to) <= 0;
|
|
152
|
+
});
|
|
153
|
+
if (!selected.length) {
|
|
154
|
+
console.log(
|
|
155
|
+
`No migrations for ${pkg} in range (${from}, ${to}]. Nothing to do.`,
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return selected;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// `run <id>`
|
|
162
|
+
const id = positional[0];
|
|
163
|
+
if (!id) fail('run requires a migration <id>, or --since <ver>');
|
|
164
|
+
const found = migrations.find((m) => m.id === id);
|
|
165
|
+
if (!found) fail(`unknown migration "${id}". Run "webentor-codemods list".`);
|
|
166
|
+
return [found];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function main() {
|
|
170
|
+
const [, , command, ...rest] = process.argv;
|
|
171
|
+
const { positional, flags } = parseArgs(rest);
|
|
172
|
+
|
|
173
|
+
if (!command || command === 'help' || flags.help) {
|
|
174
|
+
console.log(
|
|
175
|
+
[
|
|
176
|
+
'webentor-codemods — reusable codemods for Webentor Stack consumer projects',
|
|
177
|
+
'',
|
|
178
|
+
'Commands:',
|
|
179
|
+
' list List available migrations',
|
|
180
|
+
' run <id> [--path <dir>] [--apply] Run one migration (dry-run by default)',
|
|
181
|
+
' run --since <ver> [--to <ver>] Run every migration in a version range',
|
|
182
|
+
' [--package <name>] [--path <dir>] [--apply]',
|
|
183
|
+
'',
|
|
184
|
+
'Run from your project root; --path defaults to the current directory.',
|
|
185
|
+
].join('\n'),
|
|
186
|
+
);
|
|
187
|
+
process.exit(command ? 0 : 1);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const registry = loadRegistry();
|
|
191
|
+
|
|
192
|
+
if (command === 'list') {
|
|
193
|
+
printList(registry);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (command === 'run') {
|
|
198
|
+
const targetPath = resolve(flags.path || process.cwd());
|
|
199
|
+
if (!existsSync(targetPath)) fail(`--path does not exist: ${targetPath}`);
|
|
200
|
+
const apply = Boolean(flags.apply);
|
|
201
|
+
const toRun = resolveMigrationsToRun(registry, flags, positional);
|
|
202
|
+
let ok = true;
|
|
203
|
+
for (const m of toRun) {
|
|
204
|
+
if (!runMigration(m, { targetPath, apply })) ok = false;
|
|
205
|
+
}
|
|
206
|
+
if (!apply && toRun.length) {
|
|
207
|
+
console.log('\nDry-run complete. Re-run with --apply to write changes.');
|
|
208
|
+
}
|
|
209
|
+
process.exit(ok ? 0 : 1);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
fail(`unknown command "${command}". Run "webentor-codemods help".`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
main();
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# `0.13.0` — upgrade a consumer theme to webentor-core 0.13.0
|
|
2
|
+
|
|
3
|
+
**Applies to:** consumer themes moving `webentor-core` `0.12.x` → `0.13.0`
|
|
4
|
+
(WordPress 7.0 / PHP 8.4 compatibility pass).
|
|
5
|
+
|
|
6
|
+
Run from your project root:
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm dlx @webikon/webentor-codemods run 0.13.0 # preview (dry-run)
|
|
10
|
+
pnpm dlx @webikon/webentor-codemods run 0.13.0 --apply # apply
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Then reinstall + rebuild + clear caches:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
# in the theme dir
|
|
17
|
+
pnpm install && composer update
|
|
18
|
+
pnpm build
|
|
19
|
+
wp acorn optimize:clear
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This migration has two rule sets: an **editor-asset enqueue** change to
|
|
23
|
+
`app/setup.php`, and a **dependency** bump set across `package.json` +
|
|
24
|
+
`composer.json`.
|
|
25
|
+
|
|
26
|
+
## 1. Editor-asset enqueue (`rules/editor-enqueue-iframe.yml`, PHP)
|
|
27
|
+
|
|
28
|
+
Since WP 6.9/7.0 the block editor renders inside an iframe. Global canvas styles
|
|
29
|
+
must be registered on `enqueue_block_assets` (not `enqueue_block_editor_assets`)
|
|
30
|
+
so WordPress routes them **into** the iframe — otherwise it warns the style was
|
|
31
|
+
"added to the iframe incorrectly" and the styles never reach the canvas (e.g.
|
|
32
|
+
button styles missing in the editor). The editor **JavaScript** still belongs on
|
|
33
|
+
`enqueue_block_editor_assets` (it loads in the outer editor document).
|
|
34
|
+
|
|
35
|
+
In the theme's `app/setup.php`:
|
|
36
|
+
|
|
37
|
+
```php
|
|
38
|
+
add_action('enqueue_block_editor_assets', function (): void {
|
|
39
|
+
$dependencies = …;
|
|
40
|
+
\Kucrut\Vite\enqueue_asset(…, 'resources/scripts/editor.ts', …); // JS
|
|
41
|
+
\Kucrut\Vite\enqueue_asset(…, 'resources/styles/editor.css', …); // CSS
|
|
42
|
+
\Kucrut\Vite\enqueue_asset(…, 'resources/core-components/button/button.style.css', …); // CSS
|
|
43
|
+
}, 10);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
becomes:
|
|
47
|
+
|
|
48
|
+
```php
|
|
49
|
+
add_action('enqueue_block_editor_assets', function (): void {
|
|
50
|
+
$dependencies = …;
|
|
51
|
+
\Kucrut\Vite\enqueue_asset(…, 'resources/scripts/editor.ts', …); // JS stays
|
|
52
|
+
}, 10);
|
|
53
|
+
|
|
54
|
+
add_action('enqueue_block_assets', function (): void {
|
|
55
|
+
if (!is_admin()) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
\Kucrut\Vite\enqueue_asset(…, 'resources/styles/editor.css', …); // CSS moved
|
|
59
|
+
\Kucrut\Vite\enqueue_asset(…, 'resources/core-components/button/button.style.css', …); // CSS moved
|
|
60
|
+
}, 10);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The `enqueue_asset` directory + options arguments are preserved verbatim (matched
|
|
64
|
+
via metavariables), so per-project tweaks to those options survive.
|
|
65
|
+
|
|
66
|
+
- **Idempotent / conservative:** an already-migrated `setup.php` (no styles left
|
|
67
|
+
on that hook) does not match; a heavily customized hook also won't match and is
|
|
68
|
+
left untouched — migrate it by hand using the before/after above.
|
|
69
|
+
|
|
70
|
+
## 2. Dependencies (`rules/deps.yml`, JSON)
|
|
71
|
+
|
|
72
|
+
Rewrites the theme's dependency ranges to the **0.13.0 baseline** — the complete
|
|
73
|
+
set that changed from theme 2.0.6 / core 0.12 → 0.13. Each rule matches a
|
|
74
|
+
dependency by its exact key (with a value-is-string guard, so config objects that
|
|
75
|
+
share a name like `lint-staged`/`prettier`/`stylelint` are never touched) and is
|
|
76
|
+
scoped to `package.json` / `composer.json` via `files:`.
|
|
77
|
+
|
|
78
|
+
| manifest | dependency | → range |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| package.json + composer.json | webentor-core | `^0.13.0` / `^0.13` |
|
|
81
|
+
| package.json | `@wordpress/components` (major 30→35) | `^35.0.1` |
|
|
82
|
+
| package.json | `@wordpress/icons` (major 11→14) | `^14.0.1` |
|
|
83
|
+
| package.json | `stylelint` (major 16→17) | `^17.13.0` |
|
|
84
|
+
| package.json | `stylelint-config-recommended` (major 17→18) | `^18.0.0` |
|
|
85
|
+
| package.json | `@types/wordpress__block-editor` (major 14→15) | `^15.0.6` |
|
|
86
|
+
| package.json | `prettier-plugin-tailwindcss` (0.7→0.8) | `^0.8.0` |
|
|
87
|
+
| package.json | other `@wordpress/*`, `tailwindcss`/`@tailwindcss/*`, `@10up/block-components`, `@alpinejs/intersect`, `@vitejs/plugin-react`, `@roots/vite-plugin`, `vite`, `prettier`, `postcss`, `typescript-eslint`, `eslint`/`@eslint/js`, `eslint-plugin-prettier`, `lint-staged`, `@ianvs/prettier-plugin-sort-imports`, `@shufo/prettier-plugin-blade` | 0.13.0 ranges |
|
|
88
|
+
|
|
89
|
+
**Held back (not changed):** `react`/`react-dom` (18 — WordPress runtime is React
|
|
90
|
+
18), `eslint`/`@eslint/js` major (10 — blocked by `eslint-plugin-react`), `vite`
|
|
91
|
+
major (8), `typescript` major (6), `lint-staged` major (17 — needs Node 22).
|
|
92
|
+
`name`/`version` are never touched.
|
|
93
|
+
|
|
94
|
+
- **Idempotent:** re-running rewrites to the same range → no diff.
|
|
95
|
+
- **Baseline caveat:** the fix pins the 0.13.0 ranges, so a project already
|
|
96
|
+
*ahead* of the baseline within a major would be set back to it. Expected for a
|
|
97
|
+
0.12 → 0.13 upgrade; adjust by hand if you intentionally run newer.
|
|
98
|
+
|
|
99
|
+
After applying, run `pnpm install` + `composer update` to refresh the lockfiles.
|