@plaudit/webpack-extensions 2.61.2 → 2.62.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.
@@ -0,0 +1,440 @@
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.PlainEntrypointsStyleBlockJSONPlugin = void 0;
7
+ const node_crypto_1 = __importDefault(require("node:crypto"));
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ const shared_1 = require("../shared");
11
+ const php_writer_1 = require("../utils/php-writer");
12
+ const pseduo_semaphore_1 = require("../utils/pseduo-semaphore");
13
+ const UnifiedLoaderGenerator_1 = require("./UnifiedLoaderGenerator");
14
+ const webpack_1 = require("webpack");
15
+ class PlainEntrypointsStyleBlockJSONPlugin {
16
+ config;
17
+ blocksDest;
18
+ webpackRemoveEmptyScriptsPlugin;
19
+ static semaphore = new pseduo_semaphore_1.PseudoSemaphore({ collatableWorkableBlockInfo: {}, blocksDest: "", emittingWpmlXml: false }, "Block JSON v3");
20
+ static phaseTwoAttached = {};
21
+ id;
22
+ libraryType;
23
+ constructor(config, blocksDest, webpackRemoveEmptyScriptsPlugin) {
24
+ this.config = config;
25
+ this.blocksDest = blocksDest;
26
+ this.webpackRemoveEmptyScriptsPlugin = webpackRemoveEmptyScriptsPlugin;
27
+ this.id = Math.random().toString();
28
+ this.libraryType = `block-json-${this.blocksDest}`;
29
+ PlainEntrypointsStyleBlockJSONPlugin.semaphore.register(this.id);
30
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.register(this.id);
31
+ }
32
+ apply(compiler) {
33
+ webpack_1.library.EnableLibraryPlugin.setEnabled(compiler, this.libraryType);
34
+ compiler.hooks.compilation.tap(this.constructor.name, compilation => {
35
+ PlainEntrypointsStyleBlockJSONPlugin.phaseTwoAttached[this.blocksDest] = false;
36
+ PlainEntrypointsStyleBlockJSONPlugin.semaphore.reset(this.id);
37
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reset(this.id);
38
+ compilation.hooks.beforeChunkIds.tap(this.constructor.name, () => {
39
+ if (!PlainEntrypointsStyleBlockJSONPlugin.phaseTwoAttached[this.blocksDest]) {
40
+ PlainEntrypointsStyleBlockJSONPlugin.phaseTwoAttached[this.blocksDest] = true;
41
+ compilation.hooks.processAssets.tapPromise({ name: `${this.constructor.name}_CompileLoader`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT }, async () => {
42
+ const allSemaphoreData = (await PlainEntrypointsStyleBlockJSONPlugin.semaphore.wait())
43
+ .reduce((acc, cur) => {
44
+ (acc[cur.blocksDest] ?? (acc[cur.blocksDest] = [])).push(cur);
45
+ return acc;
46
+ }, {});
47
+ const semaphoreData = allSemaphoreData[this.blocksDest];
48
+ if (semaphoreData === undefined) {
49
+ compilation.errors.push(new Error(`Semaphore data missing for ${this.blocksDest}`));
50
+ return;
51
+ }
52
+ const workableBlockInfo = semaphoreData.map(sd => sd.collatableWorkableBlockInfo)
53
+ .reduce((acc, cur) => {
54
+ for (const [k, v] of Object.entries(cur)) {
55
+ if (acc[k]) {
56
+ acc[k].workableBlockEntrypointsInfo.push(...v.workableBlockEntrypointsInfo);
57
+ if (!acc[k].sourcePath && v.sourcePath) {
58
+ acc[k].sourcePath = v.sourcePath;
59
+ }
60
+ }
61
+ else {
62
+ acc[k] = { ...v, workableBlockEntrypointsInfo: [...v.workableBlockEntrypointsInfo] };
63
+ }
64
+ acc[k].workableBlockEntrypointsInfo.sort((a, b) => {
65
+ return a.handle.localeCompare(b.handle) || a.entrypointField.localeCompare(b.entrypointField);
66
+ });
67
+ }
68
+ return acc;
69
+ }, {});
70
+ const blockData = this.transformBlocks(compilation, workableBlockInfo, semaphoreData.some(sd => sd.emittingWpmlXml));
71
+ this.emitBlockLoaderFile(compilation, blockData);
72
+ });
73
+ }
74
+ });
75
+ compilation.hooks.processAssets.tapPromise({ name: this.constructor.name, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE, additionalAssets: true }, async (assets) => {
76
+ if (!("assets.json" in assets)) {
77
+ return;
78
+ }
79
+ try {
80
+ const rawAssetDataSource = assets["assets.json"]?.source();
81
+ if (typeof rawAssetDataSource !== 'string') {
82
+ PlainEntrypointsStyleBlockJSONPlugin.semaphore.reject(this.id);
83
+ compilation.errors.push(new Error("assets.json is unexpectedly missing or not a string"));
84
+ return;
85
+ }
86
+ const assetDataSource = JSON.parse(rawAssetDataSource);
87
+ if (!(0, shared_1.isRawAssetData)(assetDataSource)) {
88
+ PlainEntrypointsStyleBlockJSONPlugin.semaphore.reject(this.id);
89
+ compilation.errors.push(new Error("assets.json is does not match the RawAssetData format"));
90
+ return;
91
+ }
92
+ const applicableBlockJsonFiles = {};
93
+ compilation.modules.values()
94
+ .filter(mod => mod.type === 'json')
95
+ .flatMap(mod => compilation.chunkGraph.getModuleChunks(mod))
96
+ .filter(chunk => {
97
+ const entryOptions = chunk.getEntryOptions();
98
+ return entryOptions?.library?.type === this.libraryType && entryOptions.library.name === "block-json-inclusion-assurance";
99
+ })
100
+ .flatMap(chunk => chunk.files.values().toArray())
101
+ .forEach(danglingBlockJsFile => {
102
+ compilation.deleteAsset(danglingBlockJsFile);
103
+ });
104
+ const relevantEntrypoints = compilation.entrypoints.values()
105
+ .map(entrypoint => {
106
+ const entrypointChunk = entrypoint.getEntrypointChunk();
107
+ const entrypointLibrary = entrypointChunk.getEntryOptions()?.library;
108
+ if (entrypointLibrary?.type !== this.libraryType) {
109
+ return undefined;
110
+ }
111
+ const srcPath = entrypoint.origins[0]?.request;
112
+ if (!srcPath) {
113
+ return undefined;
114
+ }
115
+ return { entrypoint, entrypointChunk, entrypointLibrary, srcPath };
116
+ })
117
+ .filter(item => item !== undefined)
118
+ .toArray();
119
+ const blockJsonOriginToOutputMapping = {};
120
+ for (const { entrypoint, entrypointChunk, entrypointLibrary, srcPath } of relevantEntrypoints) {
121
+ if (node_path_1.default.basename(srcPath).toLowerCase() !== "block.json" || entrypointLibrary.name !== "block-json-inclusion-assurance") {
122
+ continue;
123
+ }
124
+ const asset = [...compilation.chunkGraph.getChunkEntryModulesIterable(entrypointChunk)][0]?.originalSource();
125
+ if (asset) {
126
+ //TODO: Can we guarantee that entrypoint.name is always non-null?
127
+ const epBlockJson = entrypoint.name + ".json";
128
+ if (!applicableBlockJsonFiles[epBlockJson]) {
129
+ applicableBlockJsonFiles[epBlockJson] = { sourcePath: srcPath, workableBlockEntrypointsInfo: [] };
130
+ }
131
+ blockJsonOriginToOutputMapping[srcPath] = epBlockJson;
132
+ compilation.emitAsset(epBlockJson, asset);
133
+ }
134
+ }
135
+ for (const { entrypoint, entrypointChunk, entrypointLibrary, srcPath } of relevantEntrypoints) {
136
+ if (node_path_1.default.basename(srcPath).toLowerCase() === "block.json" && entrypointLibrary.name === "block-json-inclusion-assurance") {
137
+ continue;
138
+ }
139
+ const blockEntrypointInfo = (0, shared_1.unpackSmuggledBlockEntrypointInfo)(entrypointLibrary);
140
+ if (!blockEntrypointInfo) {
141
+ continue;
142
+ }
143
+ const epBlockJson = entrypointChunk.auxiliaryFiles.values().find(auxFile => node_path_1.default.basename(auxFile) === "block.json")
144
+ ?? blockJsonOriginToOutputMapping[blockEntrypointInfo.blockJsonOrigin];
145
+ if (epBlockJson) {
146
+ //TODO: Do we need to handle a single entrypoint potentially emitting multiple primary files?
147
+ const assetData = entrypointChunk.files.values().map(file => assetDataSource[file])
148
+ .find(assetData => assetData !== undefined);
149
+ if (!assetData) {
150
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`assets.json did not contain information for ${srcPath}`, srcPath));
151
+ continue;
152
+ }
153
+ const workableBlockEntrypointsInfo = entrypoint.getFiles()
154
+ .map(file => this.stripOffBlocksDestPrefix(file))
155
+ .filter(file => !this.webpackRemoveEmptyScriptsPlugin['trash'].includes(node_path_1.default.join(this.blocksDest, file)))
156
+ .map(file => [file, (0, shared_1.scriptOrStyleTest)(file, shared_1.scriptExtension)])
157
+ .filter((item) => item[1] !== '')
158
+ .map(([file, assetType]) => {
159
+ const wasOriginallyAStyleField = (0, shared_1.isStyleField)(blockEntrypointInfo.entrypointField);
160
+ if (wasOriginallyAStyleField !== (assetType === "style")) { // This means that the file is extracted
161
+ return {
162
+ ...blockEntrypointInfo, outputPath: file, assetData, originalValue: undefined, hash: entrypointChunk.hash ?? "",
163
+ entrypointField: (0, shared_1.convertEntrypointFieldForAssetType)(blockEntrypointInfo.entrypointField, assetType)
164
+ };
165
+ }
166
+ return ({ ...blockEntrypointInfo, outputPath: file, assetData, hash: entrypointChunk.hash ?? "" });
167
+ });
168
+ if (applicableBlockJsonFiles[epBlockJson]) {
169
+ applicableBlockJsonFiles[epBlockJson].workableBlockEntrypointsInfo.push(...workableBlockEntrypointsInfo);
170
+ }
171
+ else {
172
+ applicableBlockJsonFiles[epBlockJson] = { sourcePath: workableBlockEntrypointsInfo[0]?.blockJsonOrigin, workableBlockEntrypointsInfo: workableBlockEntrypointsInfo };
173
+ }
174
+ }
175
+ }
176
+ compilation.deleteAsset("assets.json");
177
+ PlainEntrypointsStyleBlockJSONPlugin.semaphore.resolve(this.id, {
178
+ collatableWorkableBlockInfo: applicableBlockJsonFiles, blocksDest: this.blocksDest,
179
+ emittingWpmlXml: compilation.getAsset(node_path_1.default.join(this.blocksDest, "wpml-config.xml")) !== undefined
180
+ });
181
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.resolve(this.id, Object.keys(applicableBlockJsonFiles).length ? {
182
+ group: this.libraryType,
183
+ requiresBaseURI: false,
184
+ action: writer => writer.append(`require_once __DIR__.${php_writer_1.Expr.convertJsonToPHP("/" + node_path_1.default.join(this.blocksDest, "blockdir-loader.php"))};`)
185
+ } : undefined);
186
+ }
187
+ catch (e) {
188
+ PlainEntrypointsStyleBlockJSONPlugin.semaphore.reject(this.id);
189
+ UnifiedLoaderGenerator_1.UnifiedLoaderGenerator.semaphore.reject(this.id);
190
+ throw e;
191
+ }
192
+ });
193
+ });
194
+ }
195
+ emitBlockLoaderFile(compilation, blockData) {
196
+ if (this.config.useUnifiedLoader) {
197
+ const metadata = blockData['__metadata'];
198
+ delete blockData['__metadata'];
199
+ new php_writer_1.PHPWriter()
200
+ .action("init", writer => {
201
+ writer.call("\\Plaudit\\Common\\ACF\\BlockManager::autoloadSubfoldersV3", [php_writer_1.Expr.__DIR__, new php_writer_1.Expr((0, shared_1.makeEmittableConfigPHP)(blockData, false, "\t")),
202
+ php_writer_1.Expr.__FILE__, new php_writer_1.Expr((0, shared_1.makeEmittableConfigPHP)(metadata, false, "\t")), null]);
203
+ }, { accountForAlreadyDoing: true })
204
+ .emitAsset(compilation, node_path_1.default.join(this.blocksDest, "blockdir-loader.php"));
205
+ }
206
+ else {
207
+ compilation.emitAsset(node_path_1.default.join(this.blocksDest, "blockdir.config.php"), new webpack_1.sources.RawSource((0, shared_1.makeEmittableConfigPHP)(blockData, true)));
208
+ }
209
+ }
210
+ transformBlocks(compilation, collatedWorkableBlockInfo, emittingWpmlXml) {
211
+ const handleData = Object.values(collatedWorkableBlockInfo)
212
+ .flatMap(bi => bi.workableBlockEntrypointsInfo)
213
+ .sort((a, b) => a.handle.localeCompare(b.handle) || a.entrypointField.localeCompare(b.entrypointField));
214
+ const blockData = {};
215
+ for (const [blockJsonAssetName, { sourcePath: blockJsonSourcePath, workableBlockEntrypointsInfo }] of Object.entries(collatedWorkableBlockInfo)) {
216
+ if (!blockJsonSourcePath) {
217
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`${blockJsonAssetName} does not have a source path`, blockJsonAssetName));
218
+ continue;
219
+ }
220
+ const sourceDir = node_path_1.default.dirname(blockJsonSourcePath);
221
+ const outputDir = node_path_1.default.join(compilation.compiler.outputPath, node_path_1.default.dirname(blockJsonAssetName));
222
+ const blockJsonText = PlainEntrypointsStyleBlockJSONPlugin.extractAssetSource(compilation, blockJsonAssetName);
223
+ if (!blockJsonText) {
224
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Unable to extract the source for ${blockJsonAssetName}`, node_path_1.default.join(sourceDir, 'block.json')));
225
+ continue;
226
+ }
227
+ const blockJson = JSON.parse(blockJsonText);
228
+ const pathsNeedRemapping = !this.config.standaloneBlocks && blockJson["plaudit"] !== "simple";
229
+ PlainEntrypointsStyleBlockJSONPlugin.remapReferencedPHPFilesOnKey(blockJson, "setup", pathsNeedRemapping, sourceDir, outputDir, compilation, true);
230
+ PlainEntrypointsStyleBlockJSONPlugin.remapReferencedPHPFilesOnKey(blockJson, "variations", pathsNeedRemapping, sourceDir, outputDir, compilation, false);
231
+ PlainEntrypointsStyleBlockJSONPlugin.normalizeRenderTemplate(blockJson, pathsNeedRemapping, sourceDir, outputDir, compilation);
232
+ const hashForVersion = PlainEntrypointsStyleBlockJSONPlugin
233
+ .hashThingForAsset([blockJsonText, ...workableBlockEntrypointsInfo.map(bi => bi.hash)].join("~"));
234
+ if (blockJson["version"]) {
235
+ blockJson["version"] = `${blockJson["version"]}-${hashForVersion}`;
236
+ }
237
+ else {
238
+ blockJson["version"] = hashForVersion;
239
+ }
240
+ const blockDirName = node_path_1.default.dirname(node_path_1.default.relative(this.blocksDest, blockJsonAssetName));
241
+ blockData[blockDirName] = PlainEntrypointsStyleBlockJSONPlugin
242
+ .doFileOrHandleReplacements(compilation, Object.fromEntries(Object.entries(blockJson).filter(([k]) => k !== '$schema')), workableBlockEntrypointsInfo, epi => epi.handle);
243
+ compilation[blockJsonAssetName in compilation.assets ? 'updateAsset' : 'emitAsset'](blockJsonAssetName, new webpack_1.sources.RawSource(JSON.stringify(PlainEntrypointsStyleBlockJSONPlugin
244
+ .doFileOrHandleReplacements(compilation, blockJson, workableBlockEntrypointsInfo, epi => "file:./" + node_path_1.default.relative(blockDirName, epi.outputPath)), undefined, " ")));
245
+ }
246
+ return {
247
+ __metadata: {
248
+ version: 3,
249
+ "wpml-config": emittingWpmlXml,
250
+ scriptHandles: Object.fromEntries(PlainEntrypointsStyleBlockJSONPlugin
251
+ .convertToScriptHandles(handleData.filter(hd => !(0, shared_1.isStyleField)(hd.entrypointField) && !(0, shared_1.isScriptModuleField)(hd.entrypointField)))),
252
+ scriptModuleHandles: Object.fromEntries(PlainEntrypointsStyleBlockJSONPlugin
253
+ .convertToScriptHandles(handleData.filter(hd => !(0, shared_1.isStyleField)(hd.entrypointField) && (0, shared_1.isScriptModuleField)(hd.entrypointField)))),
254
+ styleHandles: Object.fromEntries(handleData.filter(hd => (0, shared_1.isStyleField)(hd.entrypointField))
255
+ .map(hd => [hd.handle, { src: hd.outputPath, rest: [hd.assetData.dependencies, hd.assetData.version] }]))
256
+ },
257
+ ...Object.fromEntries(Object.entries(blockData).sort((a, b) => a[0].localeCompare(b[0])))
258
+ };
259
+ }
260
+ static extractAssetSource(compilation, assetName) {
261
+ const assetSource = compilation.getAsset(assetName)?.source.source();
262
+ return typeof assetSource === 'string' ? assetSource : assetSource?.toString('utf-8');
263
+ }
264
+ static convertToScriptHandles(handleData) {
265
+ return handleData.map(hd => {
266
+ return [hd.handle, { src: hd.outputPath, rest: hd.entrypointField.startsWith("editor")
267
+ ? [hd.assetData.dependencies, hd.assetData.version] : [hd.assetData.dependencies, hd.assetData.version, { strategy: "defer" }] }];
268
+ });
269
+ }
270
+ static doFileOrHandleReplacements(compilation, blockJson, workableBlockEntrypointsInfo, getter) {
271
+ for (const entrypointInfo of workableBlockEntrypointsInfo) {
272
+ const fieldValue = blockJson[entrypointInfo.entrypointField];
273
+ if (!fieldValue) {
274
+ blockJson[entrypointInfo.entrypointField] = getter(entrypointInfo);
275
+ }
276
+ else if (entrypointInfo.originalValue) {
277
+ if (entrypointInfo.originalValue === fieldValue) {
278
+ blockJson[entrypointInfo.entrypointField] = getter(entrypointInfo);
279
+ }
280
+ else if (typeof fieldValue === 'string') {
281
+ blockJson[entrypointInfo.entrypointField] = [fieldValue, getter(entrypointInfo)];
282
+ }
283
+ else if (Array.isArray(fieldValue)) {
284
+ const replacementPos = fieldValue.indexOf(entrypointInfo.originalValue);
285
+ if (replacementPos === -1) {
286
+ compilation.warnings.push((0, shared_1.newWebpackErrorForFile)(`Unable to find ${entrypointInfo.originalValue} in ${entrypointInfo.entrypointField}`, entrypointInfo.blockJsonOrigin));
287
+ blockJson[entrypointInfo.entrypointField] = fieldValue.concat(getter(entrypointInfo));
288
+ }
289
+ else {
290
+ blockJson[entrypointInfo.entrypointField] = fieldValue.toSpliced(replacementPos, 1, getter(entrypointInfo));
291
+ }
292
+ }
293
+ else {
294
+ blockJson[entrypointInfo.entrypointField] = getter(entrypointInfo);
295
+ }
296
+ }
297
+ else {
298
+ if (typeof fieldValue === 'string') {
299
+ blockJson[entrypointInfo.entrypointField] = [fieldValue, getter(entrypointInfo)];
300
+ }
301
+ else if (Array.isArray(fieldValue)) {
302
+ blockJson[entrypointInfo.entrypointField] = fieldValue.concat(getter(entrypointInfo));
303
+ }
304
+ else {
305
+ blockJson[entrypointInfo.entrypointField] = getter(entrypointInfo);
306
+ }
307
+ }
308
+ }
309
+ return blockJson;
310
+ }
311
+ stripOffBlocksDestPrefix(file) {
312
+ file = node_path_1.default.normalize(file);
313
+ return this.blocksDest && file.startsWith(this.blocksDest + "/") ? file.substring(this.blocksDest.length + 1 /* we also need to drop the "/" */) : file;
314
+ }
315
+ static hashThingForAsset(thing) {
316
+ return node_crypto_1.default.createHash('md5').update(thing).digest("hex").substring(0, 20).toLowerCase();
317
+ }
318
+ static stripFilePrefix(file) {
319
+ return file.startsWith("file:./") ? file.substring(7) : file;
320
+ }
321
+ static findCommonAncestor(...paths) {
322
+ return paths.map(p => node_path_1.default.normalize(p).split(node_path_1.default.sep)).reduce((prior, current) => {
323
+ for (let i = 0, limit = Math.min(prior.length, current.length); i < limit; i++) {
324
+ if (prior[i] !== current[i]) {
325
+ return prior.slice(0, i);
326
+ }
327
+ }
328
+ return current.length < prior.length ? current : prior;
329
+ });
330
+ }
331
+ static findRelativeRouteBetween(path1, path2) {
332
+ const commonAncestor = PlainEntrypointsStyleBlockJSONPlugin.findCommonAncestor(path1, path2);
333
+ const route = Array(path1.split(node_path_1.default.sep).length - commonAncestor.length).fill("..");
334
+ route.push(node_path_1.default.relative(commonAncestor.join(node_path_1.default.sep), path2));
335
+ return route.join(node_path_1.default.sep);
336
+ }
337
+ static remapReferencedPHPFilesOnKey(blockJson, key, pathsNeedRemapping, sourceDir, outputDir, compilation, inPlaudit) {
338
+ const rawValue = (inPlaudit ? blockJson["plaudit"] : blockJson)?.[key];
339
+ let rawFiles;
340
+ let deleteOnEmpty = true;
341
+ if (typeof rawValue === 'string') {
342
+ rawFiles = [rawValue];
343
+ }
344
+ else if (Array.isArray(rawValue) && rawValue.length > 0) {
345
+ const fileReferences = rawValue.filter((value) => typeof value === 'string' && value.startsWith("file:./"));
346
+ if (fileReferences.length === rawValue.length) {
347
+ rawFiles = fileReferences;
348
+ }
349
+ else {
350
+ if (fileReferences.length !== 0) {
351
+ compilation.warnings.push((0, shared_1.newWebpackErrorForFile)(`Encountered a block with a mixture of file-reference and non-file-reference elements in the "${inPlaudit ? 'plaudit.' : ''}${key}" property`, node_path_1.default.join(sourceDir, 'block.json')));
352
+ rawFiles = fileReferences;
353
+ }
354
+ else {
355
+ rawFiles = [`${key}.php`]; // We want to emit an error if both an appropriately-named file AND an incompatible value exist, so we still need to do the check
356
+ }
357
+ deleteOnEmpty = false;
358
+ }
359
+ }
360
+ else {
361
+ if (rawValue && (!Array.isArray(rawValue) || rawValue.length === 0)) {
362
+ deleteOnEmpty = false;
363
+ }
364
+ rawFiles = [`${key}.php`];
365
+ }
366
+ const mappedFiles = pathsNeedRemapping
367
+ ? rawFiles
368
+ .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, PlainEntrypointsStyleBlockJSONPlugin.stripFilePrefix(p))))
369
+ .filter(p => node_fs_1.default.existsSync(p))
370
+ .map(p => `file:./${PlainEntrypointsStyleBlockJSONPlugin.findRelativeRouteBetween(outputDir, p)}`)
371
+ : rawFiles
372
+ .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, PlainEntrypointsStyleBlockJSONPlugin.stripFilePrefix(p)))));
373
+ if (mappedFiles.length === 0) {
374
+ if (deleteOnEmpty && rawValue !== undefined) {
375
+ delete (inPlaudit ? blockJson["plaudit"] : blockJson)[key];
376
+ }
377
+ }
378
+ else {
379
+ if (inPlaudit && typeof blockJson["plaudit"] !== 'object') {
380
+ if (blockJson["plaudit"] === "native") {
381
+ blockJson["plaudit"] = { type: "native" };
382
+ }
383
+ else {
384
+ blockJson["plaudit"] = {};
385
+ }
386
+ }
387
+ (inPlaudit ? blockJson["plaudit"] : blockJson)[key] = mappedFiles.length === 1 ? mappedFiles[0] : mappedFiles;
388
+ }
389
+ }
390
+ static normalizeRenderTemplate(blockJson, pathsNeedRemapping, sourceDir, outputDir, compilation) {
391
+ if (blockJson["acf"]) {
392
+ if (blockJson["acf"]["renderTemplate"]) {
393
+ blockJson["render_template"] = blockJson["acf"]["renderTemplate"];
394
+ delete blockJson["acf"]["renderTemplate"];
395
+ }
396
+ else if (blockJson["acf"]["render_template"]) {
397
+ blockJson["render_template"] = blockJson["acf"]["render_template"];
398
+ delete blockJson["acf"]["render_template"];
399
+ }
400
+ }
401
+ const blockName = blockJson["name"]?.toString() || "non-existent/block-name";
402
+ let rawRenderTemplate = blockJson["render"] ?? blockJson["render_template"];
403
+ rawRenderTemplate = (rawRenderTemplate
404
+ ? (typeof rawRenderTemplate === 'string' ? [rawRenderTemplate] : rawRenderTemplate)
405
+ : [`${blockName.substring(blockName.indexOf('/') + 1)}.php`, "template.php", "template.twig"]);
406
+ const renderTemplate = pathsNeedRemapping
407
+ ? rawRenderTemplate
408
+ .map(p => node_path_1.default.normalize(node_path_1.default.join(sourceDir, PlainEntrypointsStyleBlockJSONPlugin.stripFilePrefix(p))))
409
+ .filter(p => node_fs_1.default.existsSync(p))
410
+ .map(p => `file:./${PlainEntrypointsStyleBlockJSONPlugin.findRelativeRouteBetween(outputDir, p)}`)
411
+ : rawRenderTemplate
412
+ .filter(p => node_fs_1.default.existsSync(node_path_1.default.normalize(node_path_1.default.join(sourceDir, PlainEntrypointsStyleBlockJSONPlugin.stripFilePrefix(p)))));
413
+ if (renderTemplate.length === 0) {
414
+ delete blockJson["render_template"];
415
+ delete blockJson["render"];
416
+ }
417
+ else {
418
+ let validTemplateLocation, invalidTemplateLocation;
419
+ if (blockJson["acf"] || (blockJson["plaudit"] && (blockJson["plaudit"] !== "native" && (typeof blockJson["plaudit"] !== 'object' || blockJson["plaudit"]?.["type"] !== "native")))) {
420
+ // ACF-like blocks need to have the template stored in render_template.
421
+ // Because we can statically detect ACF-like blocks, we can make the move here instead of at run-time.
422
+ validTemplateLocation = "render_template";
423
+ invalidTemplateLocation = "render";
424
+ }
425
+ else {
426
+ validTemplateLocation = "render";
427
+ invalidTemplateLocation = "render_template";
428
+ }
429
+ delete blockJson[invalidTemplateLocation];
430
+ if (renderTemplate.length > 1) {
431
+ compilation.warnings.push((0, shared_1.newWebpackErrorForFile)("Encountered a block with multiple possible render files", node_path_1.default.join(sourceDir, 'block.json')));
432
+ blockJson[validTemplateLocation] = renderTemplate.find(p => p.endsWith(".php")) ?? renderTemplate[0];
433
+ }
434
+ else {
435
+ blockJson[validTemplateLocation] = renderTemplate[0];
436
+ }
437
+ }
438
+ }
439
+ }
440
+ exports.PlainEntrypointsStyleBlockJSONPlugin = PlainEntrypointsStyleBlockJSONPlugin;
@@ -5,9 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SpecialAssetHandlingPlugin = void 0;
7
7
  const node_path_1 = __importDefault(require("node:path"));
8
+ const shared_1 = require("../shared");
8
9
  const php_writer_1 = require("../utils/php-writer");
9
10
  const pseduo_semaphore_1 = require("../utils/pseduo-semaphore");
10
- const PlainEntrypointsConfigFileGeneratorPlugin_1 = require("./PlainEntrypointsConfigFileGeneratorPlugin");
11
11
  const UnifiedLoaderGenerator_1 = require("./UnifiedLoaderGenerator");
12
12
  const webpack_1 = require("webpack");
13
13
  class SpecialAssetHandlingPlugin {
@@ -91,10 +91,10 @@ class SpecialAssetHandlingPlugin {
91
91
  return;
92
92
  }
93
93
  if (!this.config.useUnifiedLoader) {
94
- PlainEntrypointsConfigFileGeneratorPlugin_1.PlainEntrypointsConfigFileGeneratorPlugin.emitResolveBaseUriFunction(writer);
94
+ (0, shared_1.emitResolveBaseUriFunction)(writer);
95
95
  }
96
96
  writer.action("wp_head", writer => {
97
- writer.call("plaudit_webpack_extensions__resolve_base_uri", [new php_writer_1.Expr('__DIR__')], { assignTo: "$base_uri" }).closePHP();
97
+ writer.call("plaudit_webpack_extensions__resolve_base_uri", [php_writer_1.Expr.__DIR__], { assignTo: "$base_uri" }).closePHP();
98
98
  for (let [filename, { preload, fetchpriority, crossorigin }] of preloadedAssets) {
99
99
  if (!preload) {
100
100
  continue;
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.UnifiedLoaderGenerator = void 0;
4
+ const shared_1 = require("../shared");
4
5
  const pseduo_semaphore_1 = require("../utils/pseduo-semaphore");
5
6
  const php_writer_1 = require("../utils/php-writer");
6
- const PlainEntrypointsConfigFileGeneratorPlugin_1 = require("./PlainEntrypointsConfigFileGeneratorPlugin");
7
7
  const webpack_1 = require("webpack");
8
8
  class UnifiedLoaderGenerator {
9
9
  config;
@@ -40,7 +40,7 @@ class UnifiedLoaderGenerator {
40
40
  compilation.hooks.afterProcessAssets.tap(this.constructor.name, () => {
41
41
  const writer = new php_writer_1.PHPWriter();
42
42
  if (writerCallbacks.some(wc => wc.requiresBaseURI)) {
43
- PlainEntrypointsConfigFileGeneratorPlugin_1.PlainEntrypointsConfigFileGeneratorPlugin.emitResolveBaseUriFunction(writer);
43
+ (0, shared_1.emitResolveBaseUriFunction)(writer);
44
44
  }
45
45
  for (const writerCallback of writerCallbacks) {
46
46
  writerCallback.action(writer);
@@ -1,13 +1,11 @@
1
- import { BlockJSONManagingPlugin } from "./BlockJSONManagingPlugin";
2
1
  import { type Compiler, type WebpackPluginInstance } from "webpack";
3
2
  export declare class WPMLConfigBuilderPlugin implements WebpackPluginInstance {
4
- private readonly blockJSONManagingPlugin;
5
3
  private readonly destDir;
6
4
  private static jsdomInstance?;
7
5
  private static domParser?;
8
6
  private static xmlSerializer?;
9
7
  private readonly parsedDocumentsCache;
10
- constructor(blockJSONManagingPlugin: BlockJSONManagingPlugin, destDir: string);
8
+ constructor(destDir: string);
11
9
  apply(compiler: Compiler): void;
12
10
  private static getJSDOMInstance;
13
11
  private static getDOMParser;
@@ -6,18 +6,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.WPMLConfigBuilderPlugin = void 0;
7
7
  const promises_1 = __importDefault(require("node:fs/promises"));
8
8
  const node_path_1 = __importDefault(require("node:path"));
9
+ const shared_1 = require("../shared");
9
10
  const jsdom_1 = require("jsdom");
10
11
  const webpack_1 = require("webpack");
11
12
  const xml_formatter_1 = __importDefault(require("xml-formatter"));
12
13
  class WPMLConfigBuilderPlugin {
13
- blockJSONManagingPlugin;
14
14
  destDir;
15
15
  static jsdomInstance;
16
16
  static domParser;
17
17
  static xmlSerializer;
18
18
  parsedDocumentsCache = new Map();
19
- constructor(blockJSONManagingPlugin, destDir) {
20
- this.blockJSONManagingPlugin = blockJSONManagingPlugin;
19
+ constructor(destDir) {
21
20
  this.destDir = destDir;
22
21
  }
23
22
  apply(compiler) {
@@ -52,7 +51,7 @@ class WPMLConfigBuilderPlugin {
52
51
  for (const category of nonMergeableCategories) {
53
52
  for (const [key, value] of Object.entries(wpmlConfig[category])) {
54
53
  if (key in mergedConfig[category]) {
55
- compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the ${category} entry named, "${key}"`, file));
54
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Already encountered a definition for the ${category} entry named, "${key}"`, file));
56
55
  }
57
56
  else {
58
57
  mergedConfig[category][key] = value;
@@ -69,7 +68,7 @@ class WPMLConfigBuilderPlugin {
69
68
  }
70
69
  catch (e) {
71
70
  if (typeof e === 'string') {
72
- compilation.errors.push(newWebpackErrorForFile(e, file));
71
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(e, file));
73
72
  }
74
73
  else {
75
74
  compilation.errors.push(e);
@@ -145,7 +144,6 @@ class WPMLConfigBuilderPlugin {
145
144
  }
146
145
  appendNamedElementsListToConfig("shortcodes", mergedConfig.shortcodes, config);
147
146
  appendNamedElementsListToConfig("taxonomies", mergedConfig.taxonomies, config);
148
- this.blockJSONManagingPlugin.additionalMetadata.set("wpml-config", true);
149
147
  compilation[wpmlEmitPath in compilation.assets ? 'updateAsset' : 'emitAsset'](wpmlEmitPath, new webpack_1.sources.RawSource(WPMLConfigBuilderPlugin.prettyPrintXML(config)));
150
148
  });
151
149
  });
@@ -205,7 +203,7 @@ class WPMLConfigBuilderPlugin {
205
203
  }
206
204
  catch (e) {
207
205
  if (typeof e === 'string') {
208
- compilation.errors.push(newWebpackErrorForFile(e, file));
206
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(e, file));
209
207
  }
210
208
  else {
211
209
  compilation.errors.push(e);
@@ -225,12 +223,12 @@ class WPMLConfigBuilderPlugin {
225
223
  const tag = child.getElementsByTagName("tag")[0];
226
224
  const shortcodeName = tag?.textContent?.trim();
227
225
  if (!shortcodeName) {
228
- compilation.errors.push(newWebpackErrorForFile(`A shortcode entry in a wpml-config.xml file is missing its tag name.`, file));
226
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`A shortcode entry in a wpml-config.xml file is missing its tag name.`, file));
229
227
  continue;
230
228
  }
231
229
  const existing = res.shortcodes[shortcodeName];
232
230
  if (existing) {
233
- compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the shortcode entry named, "${shortcodeName}"`, file));
231
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Already encountered a definition for the shortcode entry named, "${shortcodeName}"`, file));
234
232
  }
235
233
  else {
236
234
  res.shortcodes[shortcodeName] = child;
@@ -241,7 +239,7 @@ class WPMLConfigBuilderPlugin {
241
239
  importStandardTranslateOptionMap(element, file, "taxonomy", res.taxonomies, compilation);
242
240
  break;
243
241
  default:
244
- compilation.errors.push(newWebpackErrorForFile(`Unsupported element type in a wpml-config.xml file: ${element.nodeName}`, file));
242
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Unsupported element type in a wpml-config.xml file: ${element.nodeName}`, file));
245
243
  break;
246
244
  }
247
245
  }
@@ -254,17 +252,17 @@ function importStandardTranslateOptionMap(element, file, type, actionMap, compil
254
252
  for (const child of element.children) {
255
253
  const field = child.textContent;
256
254
  if (!field) {
257
- compilation.errors.push(newWebpackErrorForFile(`Encountered an empty ${type} entry in a wpml-config.xml file.`, file));
255
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Encountered an empty ${type} entry in a wpml-config.xml file.`, file));
258
256
  continue;
259
257
  }
260
258
  const translate = child.getAttribute("translate");
261
259
  if (!translate) {
262
- compilation.errors.push(newWebpackErrorForFile(`The ${type} entry for ${field} is missing the translate attribute.`, file));
260
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`The ${type} entry for ${field} is missing the translate attribute.`, file));
263
261
  continue;
264
262
  }
265
263
  const existing = actionMap[field];
266
264
  if (existing) {
267
- compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the ${type} entry named, "${field}"`, file));
265
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Already encountered a definition for the ${type} entry named, "${field}"`, file));
268
266
  }
269
267
  else {
270
268
  actionMap[field] = child;
@@ -275,17 +273,17 @@ function importStandardTranslateActionMap(element, file, type, actionMap, compil
275
273
  for (const child of element.children) {
276
274
  const field = child.textContent?.trim();
277
275
  if (!field) {
278
- compilation.errors.push(newWebpackErrorForFile(`Encountered a empty ${type} entry without a name in a wpml-config.xml file.`, file));
276
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Encountered a empty ${type} entry without a name in a wpml-config.xml file.`, file));
279
277
  continue;
280
278
  }
281
279
  const action = child.getAttribute("action");
282
280
  if (!action) {
283
- compilation.errors.push(newWebpackErrorForFile(`The ${type} entry for ${field} is missing an action.`, file));
281
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`The ${type} entry for ${field} is missing an action.`, file));
284
282
  continue;
285
283
  }
286
284
  const existing = actionMap[field];
287
285
  if (existing) {
288
- compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the ${type} entry named, "${field}"`, file));
286
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`Already encountered a definition for the ${type} entry named, "${field}"`, file));
289
287
  }
290
288
  else {
291
289
  actionMap[field] = child;
@@ -433,12 +431,6 @@ function mergeGenericSettingsKeys(existing, novel) {
433
431
  }
434
432
  return { ...existing, ...novel, keys: mergeGenericSettingsKeyLists(existing.keys, novel.keys) };
435
433
  }
436
- function newWebpackErrorForFile(error, file) {
437
- const res = new webpack_1.WebpackError(error);
438
- res.hideStack = true;
439
- res.file = file;
440
- return res;
441
- }
442
434
  function writeGenericSettingsKeys(keys, parent, document) {
443
435
  parent.append(...keys.sort((a, b) => a.name.localeCompare(b.name)).map(key => {
444
436
  const element = document.createElement("key");