@plaudit/webpack-extensions 2.39.0 → 2.41.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.
@@ -2,6 +2,7 @@ import { type Compiler, type WebpackPluginInstance } from "webpack";
2
2
  export default class AdditionalDependencyInjectorPlugin implements WebpackPluginInstance {
3
3
  private readonly entrypointAdditionalDependencies;
4
4
  private readonly processingModules;
5
- constructor(entrypointAdditionalDependencies: string[], processingModules: boolean);
5
+ private readonly addExternalizedDep;
6
+ constructor(entrypointAdditionalDependencies: string[], processingModules: boolean, addExternalizedDep: (dep: string) => void);
6
7
  apply(compiler: Compiler): void;
7
8
  }
@@ -8,53 +8,46 @@ const webpack_1 = require("webpack");
8
8
  class AdditionalDependencyInjectorPlugin {
9
9
  entrypointAdditionalDependencies;
10
10
  processingModules;
11
- constructor(entrypointAdditionalDependencies, processingModules) {
11
+ addExternalizedDep;
12
+ constructor(entrypointAdditionalDependencies, processingModules, addExternalizedDep) {
12
13
  this.entrypointAdditionalDependencies = entrypointAdditionalDependencies;
13
14
  this.processingModules = processingModules;
15
+ this.addExternalizedDep = addExternalizedDep;
14
16
  }
15
17
  apply(compiler) {
16
18
  compiler.hooks.thisCompilation.tap("AdditionalDependencyInjectorPlugin", compilation => {
17
19
  compilation.hooks.processAssets.tap({
18
- name: "AdditionalDependencyInjectorPlugin_ProcessAssets",
19
- stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ANALYSE
20
- }, compilationAssets => {
21
- const usableEntrypointTest = this.processingModules ? /\.mtsx?$/ : /\.tsx?$/;
22
- const assetSources = new Map();
20
+ name: "AdditionalDependencyInjectorPlugin_ProcessAssets_AddFakeModules",
21
+ stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
22
+ }, () => {
23
+ const usableEntrypointTest = this.processingModules ? /\.m[jt]sx?$/i : /\.[jt]sx?$/i;
23
24
  for (const entrypoint of compilation.entrypoints.values()) {
24
25
  const req = entrypoint.origins.filter(origin => usableEntrypointTest.test(origin.request))[0]?.request;
25
- if (req) {
26
- for (const chunk of entrypoint.chunks) {
27
- for (const file of chunk.files) {
28
- if (file.endsWith('.asset.php')) {
29
- assetSources.set(file, req);
30
- }
31
- }
32
- }
26
+ if (!req) {
27
+ continue;
28
+ }
29
+ const additionalDependencies = [...this.entrypointAdditionalDependencies];
30
+ const firstLine = node_fs_1.default.readFileSync(req, 'utf8').trim().split(/\r?\n/)[0];
31
+ if (firstLine?.startsWith("//ADDITIONAL_DEPENDENCIES:")) {
32
+ additionalDependencies.push(...firstLine.substring(26).trim().split(',').map(dep => dep.trim()));
33
+ }
34
+ const chunk = entrypoint.getEntrypointChunk();
35
+ for (const additionalDep of additionalDependencies) {
36
+ this.addExternalizedDep(additionalDep);
37
+ compilation.chunkGraph.connectChunkAndModule(chunk, new webpack_1.ExternalModule("__REMOVE_ME__", "", additionalDep));
33
38
  }
34
39
  }
35
- for (const [name, asset] of Object.entries(compilationAssets)) {
36
- if (name.endsWith(".asset.php") && asset.constructor.name === 'RawSource') {
37
- const assetSource = assetSources.get(name);
38
- if (!assetSource) {
39
- continue;
40
- }
41
- const additionalDependencies = [...this.entrypointAdditionalDependencies];
42
- const firstLine = node_fs_1.default.readFileSync(assetSource, 'utf8').trim().split(/\r?\n/)[0];
43
- if (firstLine?.startsWith("//ADDITIONAL_DEPENDENCIES:")) {
44
- additionalDependencies.push(...firstLine.substring(26).trim().split(',').map(dep => dep.trim()));
45
- }
46
- if (additionalDependencies.length > 0) {
47
- const seen = new Set();
48
- const additionalDeps = additionalDependencies.filter(dep => !seen.has(dep) && seen.add(dep)).sort().map(v => `'${v}'`).join(', ');
49
- if (additionalDeps.length > 0) {
50
- compilation.updateAsset(name, new webpack_1.sources.RawSource(asset.source().toString()
51
- .replaceAll(/(?:, )?'wp-[^']+\/[^']+'/gi, '')
52
- .replace(/('dependencies'\s+=>\s+(?:array\(|\[))(.*)([)\]], 'version')/g, (match, g1, g2, g3) => `${g1}${g2.length > 0 ? `${g2}, ${additionalDeps}` : additionalDeps}${g3}`)));
53
- continue;
54
- }
40
+ });
41
+ compilation.hooks.processAssets.tap({
42
+ name: "AdditionalDependencyInjectorPlugin_ProcessAssets_RemoveFakeModules",
43
+ stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_REPORT
44
+ }, () => {
45
+ for (const entrypoint of compilation.entrypoints.values()) {
46
+ const entrypointChunk = entrypoint.getEntrypointChunk();
47
+ for (const module of compilation.chunkGraph.getChunkModules(entrypointChunk)) {
48
+ if (module instanceof webpack_1.ExternalModule && module.request === '__REMOVE_ME__') {
49
+ compilation.chunkGraph.disconnectChunkAndModule(entrypointChunk, module);
55
50
  }
56
- compilation.updateAsset(name, new webpack_1.sources.RawSource(asset.source().toString()
57
- .replaceAll(/(?:, )?'wp-[^']+\/[^']+'/gi, '')));
58
51
  }
59
52
  }
60
53
  });
@@ -12,6 +12,7 @@ export default class BlockJSONManagingPlugin implements WebpackPluginInstance {
12
12
  private static readonly blockJSONAssetSourceDirs;
13
13
  private static readonly blockJsonAssetKeyMapping;
14
14
  private static readonly blockJsonAssetKeyReadinessMapping;
15
+ readonly additionalMetadata: Map<string, any>;
15
16
  constructor(standaloneBlocks: boolean, processingModules: boolean);
16
17
  static recordRawDependency(entrypoint: string, dependency: string): void;
17
18
  static recordBlockJSONAssetSourceDir(entrypoint: string, source: string): void;
@@ -21,6 +21,7 @@ class BlockJSONManagingPlugin {
21
21
  static blockJSONAssetSourceDirs = new Map();
22
22
  static blockJsonAssetKeyMapping = new Map();
23
23
  static blockJsonAssetKeyReadinessMapping = new Map();
24
+ additionalMetadata = new Map();
24
25
  constructor(standaloneBlocks, processingModules) {
25
26
  this.standaloneBlocks = standaloneBlocks;
26
27
  this.processingModules = processingModules;
@@ -37,6 +38,7 @@ class BlockJSONManagingPlugin {
37
38
  }
38
39
  apply(compiler) {
39
40
  compiler.hooks.compilation.tap(this.constructor.name, compilation => {
41
+ this.additionalMetadata.clear();
40
42
  this.registerAssetProcessor(compilation);
41
43
  if (!this.processingModules) {
42
44
  this.registerBlockJsonProcessor(compilation);
@@ -373,8 +375,46 @@ class BlockJSONManagingPlugin {
373
375
  compilation[name in compilation.assets ? 'updateAsset' : 'emitAsset'](name, new webpack_1.sources.RawSource(JSON.stringify(json, undefined, " ")));
374
376
  blockDirConfigData[node_path_1.default.dirname(name)] = json;
375
377
  }
376
- const sortedBlockDirConfigData = Object.fromEntries([["__metadata", { version: 1 }], ...Object.entries(blockDirConfigData)
377
- .sort(([a], [b]) => a.localeCompare(b))]);
378
+ let sortedBlockDirConfigData;
379
+ const blockDirConfigs = Object.entries(blockDirConfigData).sort(([a], [b]) => a.localeCompare(b));
380
+ const rawAssetDataSource = compilation.assets["assets.json"]?.source();
381
+ if (typeof rawAssetDataSource === 'string') {
382
+ const scriptHandles = {};
383
+ const styleHandles = {};
384
+ const rawAssetData = JSON.parse(rawAssetDataSource);
385
+ const mappableKeys = [...BlockJSONManagingPlugin.mappableModuleKeys, ...BlockJSONManagingPlugin.mappableNonModuleKeys];
386
+ for (const [blockFolder, config] of blockDirConfigs) {
387
+ for (const mappableKey of mappableKeys) {
388
+ const cfg = config[mappableKey];
389
+ if (cfg) {
390
+ if (Array.isArray(cfg)) {
391
+ for (let i = 0; i < cfg.length; i++) {
392
+ const assetDetails = getAssetDetails(blockFolder, cfg[i], rawAssetData);
393
+ if (assetDetails) {
394
+ (assetDetails[0] ? styleHandles : scriptHandles)[assetDetails[1]] = assetDetails[2];
395
+ cfg[i] = assetDetails[1];
396
+ }
397
+ }
398
+ }
399
+ else {
400
+ const assetDetails = getAssetDetails(blockFolder, cfg, rawAssetData);
401
+ if (assetDetails) {
402
+ (assetDetails[0] ? styleHandles : scriptHandles)[assetDetails[1]] = assetDetails[2];
403
+ config[mappableKey] = assetDetails[1];
404
+ }
405
+ }
406
+ }
407
+ }
408
+ }
409
+ sortedBlockDirConfigData = Object.fromEntries([
410
+ ["__metadata", { version: 2, ...Object.fromEntries(this.additionalMetadata.entries()), scriptHandles, styleHandles }],
411
+ ...blockDirConfigs
412
+ ]);
413
+ compilation.deleteAsset("assets.json");
414
+ }
415
+ else {
416
+ sortedBlockDirConfigData = Object.fromEntries([["__metadata", { version: 1, ...Object.fromEntries(this.additionalMetadata.entries()) }], ...blockDirConfigs]);
417
+ }
378
418
  compilation.emitAsset("blockdir.config", new webpack_1.sources.RawSource((0, php_serializer_1.default)(sortedBlockDirConfigData, { excludedKeys: ["$schema"] })));
379
419
  });
380
420
  }
@@ -447,3 +487,17 @@ function makeSync() {
447
487
  });
448
488
  return res;
449
489
  }
490
+ function getAssetDetails(blockFolder, asset, rawAssetData) {
491
+ if (!asset.startsWith("file:./")) {
492
+ return undefined;
493
+ }
494
+ const src = `${blockFolder}/${asset.substring(7)}`;
495
+ const isCss = src.endsWith(".css");
496
+ const assetData = isCss
497
+ ? rawAssetData[src.substring(0, src.length - 3) + "js"] ?? rawAssetData[src.substring(0, src.length - 3).replace("style-style", "style") + "js"]
498
+ : rawAssetData[src];
499
+ if (!assetData) {
500
+ return undefined;
501
+ }
502
+ return [isCss, src.substring(0, src.length - (isCss ? 4 : 3)), { src, rest: [assetData.dependencies, assetData.version] }];
503
+ }
@@ -0,0 +1,16 @@
1
+ import { type Compiler, type WebpackPluginInstance } from "webpack";
2
+ import BlockJSONManagingPlugin from "./BlockJSONManagingPlugin";
3
+ export default class WPMLConfigBuilder implements WebpackPluginInstance {
4
+ private readonly blockJSONManagingPlugin;
5
+ private static jsdomInstance?;
6
+ private static domParser?;
7
+ private static xmlSerializer?;
8
+ private readonly parsedDocumentsCache;
9
+ constructor(blockJSONManagingPlugin: BlockJSONManagingPlugin);
10
+ apply(compiler: Compiler): void;
11
+ private static getJSDOMInstance;
12
+ private static getDOMParser;
13
+ private static getXMLSerializer;
14
+ private static prettyPrintXML;
15
+ private loadWPMLConfigXML;
16
+ }
@@ -0,0 +1,471 @@
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
+ const promises_1 = __importDefault(require("node:fs/promises"));
7
+ const jsdom_1 = require("jsdom");
8
+ const webpack_1 = require("webpack");
9
+ const xml_formatter_1 = __importDefault(require("xml-formatter"));
10
+ class WPMLConfigBuilder {
11
+ blockJSONManagingPlugin;
12
+ static jsdomInstance;
13
+ static domParser;
14
+ static xmlSerializer;
15
+ parsedDocumentsCache = new Map();
16
+ constructor(blockJSONManagingPlugin) {
17
+ this.blockJSONManagingPlugin = blockJSONManagingPlugin;
18
+ }
19
+ apply(compiler) {
20
+ compiler.hooks.compilation.tap(this.constructor.name, compilation => {
21
+ compilation.hooks.processAssets.tapPromise({ name: `${this.constructor.name}__processXML`, stage: webpack_1.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL }, async (assets) => {
22
+ const entrypoint = compilation.entrypoints.get("wpml-config.xml");
23
+ if (!entrypoint) {
24
+ return;
25
+ }
26
+ const files = Promise.all([
27
+ Promise.all(entrypoint.origins.map(origin => origin.request).filter(request => request.endsWith("wpml-config.xml"))
28
+ .map(async (request) => this.loadWPMLConfigXML(request, compilation))),
29
+ Promise.all(entrypoint.origins.map(origin => origin.request).filter(request => request.endsWith("block.json"))
30
+ .map(async (request) => [JSON.parse(await promises_1.default.readFile(request, 'utf8')), request]))
31
+ ]);
32
+ for (const name of Object.keys(assets)) {
33
+ if (name.startsWith("wpml-config.xml")) {
34
+ compilation.deleteAsset(name);
35
+ }
36
+ }
37
+ const [wpmlConfigs, blockJsons] = await files;
38
+ if (!wpmlConfigs.length && !blockJsons.length) {
39
+ return;
40
+ }
41
+ const mergedConfig = {
42
+ customFields: {}, customTermFields: {}, customTypes: {}, gutenbergBlocks: {}, shortcodeList: new Set(), shortcodes: {}, taxonomies: {}
43
+ };
44
+ const nonMergeableCategories = ['customFields', 'customTermFields', 'customTypes', 'shortcodes', 'taxonomies'];
45
+ for (const [wpmlConfig, file] of wpmlConfigs) {
46
+ for (const category of nonMergeableCategories) {
47
+ for (const [key, value] of Object.entries(wpmlConfig[category])) {
48
+ if (key in mergedConfig[category]) {
49
+ compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the ${category} entry named, "${key}"`, file));
50
+ }
51
+ else {
52
+ mergedConfig[category][key] = value;
53
+ }
54
+ }
55
+ }
56
+ for (const shortcode of wpmlConfig.shortcodeList) {
57
+ mergedConfig.shortcodeList.add(shortcode);
58
+ }
59
+ for (const [type, block] of Object.entries(wpmlConfig.gutenbergBlocks)) {
60
+ const existing = mergedConfig.gutenbergBlocks[type];
61
+ try {
62
+ mergedConfig.gutenbergBlocks[type] = existing ? mergeWPMLGutenbergBlocks(existing, block) : block;
63
+ }
64
+ catch (e) {
65
+ if (typeof e === 'string') {
66
+ compilation.errors.push(newWebpackErrorForFile(e, file));
67
+ }
68
+ else {
69
+ compilation.errors.push(e);
70
+ }
71
+ }
72
+ }
73
+ }
74
+ for (const [blockJson, file] of blockJsons) {
75
+ const type = blockJson["name"]?.toString();
76
+ if (typeof type !== 'string') {
77
+ continue;
78
+ }
79
+ const blockConfig = { type, translate: '1', keys: [], xPaths: [] };
80
+ if (blockJson['plaudit']?.['properties']) {
81
+ const snps = blockJson['plaudit']['properties'];
82
+ if (Array.isArray(snps)) {
83
+ for (const snp of snps) {
84
+ convertSNPToKeys(snp, blockConfig.keys);
85
+ }
86
+ }
87
+ else {
88
+ convertSNPToKeys(snps, blockConfig.keys);
89
+ }
90
+ }
91
+ if (typeof blockJson['attributes'] === 'object') {
92
+ for (const [name, { translatable }] of Object.entries(blockJson['attributes'])) {
93
+ if (translatable) {
94
+ blockConfig.keys.push({ name, keys: [] });
95
+ }
96
+ }
97
+ }
98
+ const existing = mergedConfig.gutenbergBlocks[blockConfig.type];
99
+ if (blockConfig.keys.length || blockConfig.xPaths.length) {
100
+ mergedConfig.gutenbergBlocks[blockConfig.type] = existing ? mergeWPMLGutenbergBlocks(existing, blockConfig) : blockConfig;
101
+ }
102
+ else if (!existing) {
103
+ mergedConfig.gutenbergBlocks[blockConfig.type] = blockConfig;
104
+ }
105
+ }
106
+ const config = WPMLConfigBuilder.getDOMParser().parseFromString("<wpml-config></wpml-config>", "application/xml");
107
+ appendNamedElementsListToConfig("custom-fields", mergedConfig.customFields, config);
108
+ appendNamedElementsListToConfig("custom-term-fields", mergedConfig.customTermFields, config);
109
+ appendNamedElementsListToConfig("custom-types", mergedConfig.customTypes, config);
110
+ const gutenbergBlocks = Object.values(mergedConfig.gutenbergBlocks);
111
+ if (gutenbergBlocks.length) {
112
+ const gutenbergBlocksElement = config.createElement("gutenberg-blocks");
113
+ gutenbergBlocksElement.append(...gutenbergBlocks
114
+ .sort((a, b) => a.type.localeCompare(b.type))
115
+ .map(gutenbergBlock => {
116
+ const gutenbergBlockElement = config.createElement("gutenberg-block");
117
+ gutenbergBlockElement.setAttribute("type", gutenbergBlock.type);
118
+ if (gutenbergBlock.label) {
119
+ gutenbergBlockElement.setAttribute("label", gutenbergBlock.label);
120
+ }
121
+ gutenbergBlockElement.setAttribute("translate", gutenbergBlock.translate);
122
+ writeGenericSettingsKeys(gutenbergBlock.keys, gutenbergBlockElement, config);
123
+ gutenbergBlockElement.append(...gutenbergBlock.xPaths
124
+ .sort((a, b) => a.path.localeCompare(b.path))
125
+ .map(xPath => {
126
+ const xPathElement = config.createElement("xpath");
127
+ writeCommonGenericSettingsItemProps(xPathElement, xPath);
128
+ xPathElement.append(xPath.path);
129
+ return xPathElement;
130
+ }));
131
+ return gutenbergBlockElement;
132
+ }));
133
+ config.documentElement.append(gutenbergBlocksElement);
134
+ }
135
+ if (mergedConfig.shortcodeList.size) {
136
+ const node = config.createElement("shortcode-list");
137
+ node.append([...mergedConfig.shortcodeList].sort().join(","));
138
+ config.documentElement.appendChild(node);
139
+ }
140
+ appendNamedElementsListToConfig("shortcodes", mergedConfig.shortcodes, config);
141
+ appendNamedElementsListToConfig("taxonomies", mergedConfig.taxonomies, config);
142
+ this.blockJSONManagingPlugin.additionalMetadata.set("wpml-config", true);
143
+ compilation["wpml-config.xml" in compilation.assets ? 'updateAsset' : 'emitAsset']("wpml-config.xml", new webpack_1.sources.RawSource(WPMLConfigBuilder.prettyPrintXML(config)));
144
+ });
145
+ });
146
+ }
147
+ static getJSDOMInstance() {
148
+ return WPMLConfigBuilder.jsdomInstance ?? (WPMLConfigBuilder.jsdomInstance = new jsdom_1.JSDOM("", { contentType: "text/html" }));
149
+ }
150
+ static getDOMParser() {
151
+ return WPMLConfigBuilder.domParser ?? (WPMLConfigBuilder.domParser = new (WPMLConfigBuilder.getJSDOMInstance().window.DOMParser)());
152
+ }
153
+ static getXMLSerializer() {
154
+ return WPMLConfigBuilder.xmlSerializer ?? (WPMLConfigBuilder.xmlSerializer = new (WPMLConfigBuilder.getJSDOMInstance().window.XMLSerializer)());
155
+ }
156
+ static prettyPrintXML(document) {
157
+ return (0, xml_formatter_1.default)(WPMLConfigBuilder.getXMLSerializer().serializeToString(document), {
158
+ indentation: '\t',
159
+ collapseContent: true,
160
+ lineSeparator: '\n',
161
+ whiteSpaceAtEndOfSelfclosingTag: true,
162
+ forceSelfClosingEmptyTag: true,
163
+ strictMode: true,
164
+ filter(node) {
165
+ return node.type === 'Element' || node.type === 'Text';
166
+ }
167
+ });
168
+ }
169
+ async loadWPMLConfigXML(file, compilation) {
170
+ const contents = await promises_1.default.readFile(file, 'utf8');
171
+ const existing = this.parsedDocumentsCache.get(file);
172
+ if (existing?.raw === contents) {
173
+ return [existing, file];
174
+ }
175
+ const wpmlConfig = WPMLConfigBuilder.getDOMParser().parseFromString(contents.replaceAll(/\s+xmlns=['"][^'"]+['"]/sig, ""), "application/xml");
176
+ const res = { raw: contents, customFields: {}, customTermFields: {}, customTypes: {}, gutenbergBlocks: {}, shortcodeList: new Set(), shortcodes: {}, taxonomies: {} };
177
+ for (const element of wpmlConfig.documentElement.children) {
178
+ switch (element.nodeName) {
179
+ case "custom-fields":
180
+ importStandardTranslateActionMap(element, file, "custom-field", res.customFields, compilation);
181
+ break;
182
+ case "custom-term-fields":
183
+ importStandardTranslateActionMap(element, file, "custom-term-field", res.customTermFields, compilation);
184
+ break;
185
+ case "custom-types":
186
+ importStandardTranslateOptionMap(element, file, "custom-type", res.customTypes, compilation);
187
+ break;
188
+ case "gutenberg-blocks":
189
+ for (const child of element.children) {
190
+ try {
191
+ const block = convertGutenbergBlockToJSRepresentation(child);
192
+ const existing = res.gutenbergBlocks[block.type];
193
+ if (existing) {
194
+ res.gutenbergBlocks[block.type] = mergeWPMLGutenbergBlocks(existing, block);
195
+ }
196
+ else {
197
+ res.gutenbergBlocks[block.type] = block;
198
+ }
199
+ }
200
+ catch (e) {
201
+ if (typeof e === 'string') {
202
+ compilation.errors.push(newWebpackErrorForFile(e, file));
203
+ }
204
+ else {
205
+ compilation.errors.push(e);
206
+ }
207
+ }
208
+ }
209
+ break;
210
+ case "shortcode-list":
211
+ if (element.textContent) {
212
+ for (const shortcode of element.textContent.split(",")) {
213
+ res.shortcodeList.add(shortcode.trim());
214
+ }
215
+ }
216
+ break;
217
+ case "shortcodes":
218
+ for (const child of element.children) {
219
+ const tag = child.getElementsByTagName("tag")[0];
220
+ const shortcodeName = tag?.textContent?.trim();
221
+ if (!shortcodeName) {
222
+ compilation.errors.push(newWebpackErrorForFile(`A shortcode entry in a wpml-config.xml file is missing its tag name.`, file));
223
+ continue;
224
+ }
225
+ const existing = res.shortcodes[shortcodeName];
226
+ if (existing) {
227
+ compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the shortcode entry named, "${shortcodeName}"`, file));
228
+ }
229
+ else {
230
+ res.shortcodes[shortcodeName] = child;
231
+ }
232
+ }
233
+ break;
234
+ case "taxonomies":
235
+ importStandardTranslateOptionMap(element, file, "taxonomy", res.taxonomies, compilation);
236
+ break;
237
+ default:
238
+ compilation.errors.push(newWebpackErrorForFile(`Unsupported element type in a wpml-config.xml file: ${element.nodeName}`, file));
239
+ break;
240
+ }
241
+ }
242
+ this.parsedDocumentsCache.set(file, res);
243
+ return [res, file];
244
+ }
245
+ }
246
+ exports.default = WPMLConfigBuilder;
247
+ function importStandardTranslateOptionMap(element, file, type, actionMap, compilation) {
248
+ for (const child of element.children) {
249
+ const field = child.textContent;
250
+ if (!field) {
251
+ compilation.errors.push(newWebpackErrorForFile(`Encountered an empty ${type} entry in a wpml-config.xml file.`, file));
252
+ continue;
253
+ }
254
+ const translate = child.getAttribute("translate");
255
+ if (!translate) {
256
+ compilation.errors.push(newWebpackErrorForFile(`The ${type} entry for ${field} is missing the translate attribute.`, file));
257
+ continue;
258
+ }
259
+ const existing = actionMap[field];
260
+ if (existing) {
261
+ compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the ${type} entry named, "${field}"`, file));
262
+ }
263
+ else {
264
+ actionMap[field] = child;
265
+ }
266
+ }
267
+ }
268
+ function importStandardTranslateActionMap(element, file, type, actionMap, compilation) {
269
+ for (const child of element.children) {
270
+ const field = child.textContent?.trim();
271
+ if (!field) {
272
+ compilation.errors.push(newWebpackErrorForFile(`Encountered a empty ${type} entry without a name in a wpml-config.xml file.`, file));
273
+ continue;
274
+ }
275
+ const action = child.getAttribute("action");
276
+ if (!action) {
277
+ compilation.errors.push(newWebpackErrorForFile(`The ${type} entry for ${field} is missing an action.`, file));
278
+ continue;
279
+ }
280
+ const existing = actionMap[field];
281
+ if (existing) {
282
+ compilation.errors.push(newWebpackErrorForFile(`Already encountered a definition for the ${type} entry named, "${field}"`, file));
283
+ }
284
+ else {
285
+ actionMap[field] = child;
286
+ }
287
+ }
288
+ }
289
+ function convertSNPToKeys(prop, keys) {
290
+ if (Array.isArray(prop)) {
291
+ for (const p of prop) {
292
+ convertSNPToKeys(p, keys);
293
+ }
294
+ }
295
+ else if ('properties' in prop) {
296
+ for (const item of prop.properties) {
297
+ convertSNPToKeys(item, keys);
298
+ }
299
+ }
300
+ else if ('items' in prop) {
301
+ for (const item of prop.items) {
302
+ convertSNPToKeys(item, keys);
303
+ }
304
+ }
305
+ else {
306
+ if (prop.translatable) {
307
+ keys.push({ name: prop.name, keys: [] });
308
+ }
309
+ else if ('fields' in prop) {
310
+ if (prop.fields) {
311
+ const nestedKeys = [];
312
+ convertSNPToKeys(prop.fields, nestedKeys);
313
+ if (nestedKeys.length) {
314
+ keys.push({ name: prop.name, keys: nestedKeys });
315
+ }
316
+ }
317
+ }
318
+ else if ('itemType' in prop && Array.isArray(prop.itemType)) {
319
+ const nestedKeys = [];
320
+ convertSNPToKeys(prop.itemType, nestedKeys);
321
+ if (nestedKeys.length) {
322
+ keys.push({ name: prop.name, keys: nestedKeys });
323
+ }
324
+ }
325
+ }
326
+ }
327
+ function convertGutenbergBlockToJSRepresentation(element) {
328
+ const type = element.getAttribute("type");
329
+ if (!type) {
330
+ throw `A gutenberg-block entry in a wpml-config.xml file is missing its type attribute.`;
331
+ }
332
+ const translate = element.getAttribute("translate");
333
+ if (!translate) {
334
+ throw `The gutenberg-block entry for ${type} is missing its translate attribute.`;
335
+ }
336
+ if (translate !== '0' && translate !== '1') {
337
+ throw `The gutenberg-block entry for ${type} has an invalid translate attribute. Expected 0 or 1, but got, "${translate}"`;
338
+ }
339
+ const keys = [];
340
+ const xPaths = [];
341
+ for (const child of element.children) {
342
+ if (child.nodeName === 'key') {
343
+ keys.push(convertGenericSettingsKeyToJSRepresentation(child, `a gutenberg-block entry for ${type}`));
344
+ }
345
+ else if (child.nodeName === 'xpath') {
346
+ xPaths.push(convertGenericSettingsXPathToJSRepresentation(child, `a gutenberg-block entry for ${type}`));
347
+ }
348
+ else {
349
+ throw `The gutenberg-block entry for ${type} has an unsupported child node ("${child.nodeName}")`;
350
+ }
351
+ }
352
+ return { type, label: element.getAttribute("label"), translate, keys, xPaths };
353
+ }
354
+ function convertGenericSettingsKeyToJSRepresentation(element, containerName) {
355
+ const name = element.getAttribute("name");
356
+ if (!name) {
357
+ throw `Encountered a key without a name in ${containerName}.`;
358
+ }
359
+ let encoding = element.getAttribute("encoding");
360
+ if (encoding && encoding !== 'json') {
361
+ throw `Encountered an invalid encoding on a key named, "${name}" in ${containerName}. It must be either blank or JSON`;
362
+ }
363
+ else {
364
+ encoding = null;
365
+ }
366
+ let searchMethod = element.getAttribute("searchMethod");
367
+ if (searchMethod && searchMethod !== 'wildcards' && searchMethod !== 'regex') {
368
+ throw `Encountered an invalid search-method on a key named, "${name}" in ${containerName}. It must be either blank or JSON`;
369
+ }
370
+ else {
371
+ searchMethod = null;
372
+ }
373
+ return {
374
+ name,
375
+ label: element.getAttribute("label"),
376
+ type: element.getAttribute("type"),
377
+ subType: element.getAttribute("sub-type"),
378
+ encoding,
379
+ searchMethod,
380
+ keys: [...element.children].map(child => convertGenericSettingsKeyToJSRepresentation(child, containerName))
381
+ };
382
+ }
383
+ function convertGenericSettingsXPathToJSRepresentation(element, containerName) {
384
+ if (!element.textContent) {
385
+ throw `Encountered an empty XPath in ${containerName}.`;
386
+ }
387
+ return {
388
+ path: element.textContent,
389
+ label: element.getAttribute("label"),
390
+ type: element.getAttribute("type"),
391
+ subType: element.getAttribute("sub-type")
392
+ };
393
+ }
394
+ function mergeWPMLGutenbergBlocks(existing, novel) {
395
+ if (novel.type && existing.type !== novel.type) {
396
+ throw `Cannot merge WPML Gutenberg Blocks of differing types`;
397
+ }
398
+ if (novel.translate && existing.translate !== novel.translate) {
399
+ throw `Cannot merge WPML Gutenberg Blocks (${existing.type} and ${novel.type ?? existing.type}) with differing translate values`;
400
+ }
401
+ return {
402
+ type: existing.type,
403
+ translate: existing.translate,
404
+ label: novel.label ?? existing.label,
405
+ keys: novel.keys?.length ? (existing.keys.length ? mergeGenericSettingsKeyLists(existing.keys, novel.keys) : novel.keys) : existing.keys,
406
+ xPaths: novel.xPaths?.length ? (existing.xPaths.length ? [...existing.xPaths, ...novel.xPaths] : novel.xPaths) : existing.xPaths
407
+ };
408
+ }
409
+ function mergeGenericSettingsKeyLists(existingKeys, novelKeys) {
410
+ const keys = {};
411
+ for (const key of existingKeys) {
412
+ const existing = keys[key.name];
413
+ keys[key.name] = existing ? mergeGenericSettingsKeys(existing, key) : key;
414
+ }
415
+ for (const key of novelKeys) {
416
+ const existing = keys[key.name];
417
+ keys[key.name] = existing ? mergeGenericSettingsKeys(existing, key) : key;
418
+ }
419
+ return Object.values(keys);
420
+ }
421
+ function mergeGenericSettingsKeys(existing, novel) {
422
+ if (existing.encoding && novel.encoding && existing.encoding !== novel.encoding) {
423
+ throw `Cannot merge WPMLGenericSettingsKeys with differing encoding values (${existing.encoding} and ${novel.encoding}) on ${novel.name}.`;
424
+ }
425
+ if (existing.searchMethod && novel.searchMethod && existing.searchMethod !== novel.searchMethod) {
426
+ throw `Cannot merge WPMLGenericSettingsKeys with differing search-method values (${existing.searchMethod} and ${novel.searchMethod}) on ${novel.name}.`;
427
+ }
428
+ return { ...existing, ...novel, keys: mergeGenericSettingsKeyLists(existing.keys, novel.keys) };
429
+ }
430
+ function newWebpackErrorForFile(error, file) {
431
+ const res = new webpack_1.WebpackError(error);
432
+ res.hideStack = true;
433
+ res.file = file;
434
+ return res;
435
+ }
436
+ function writeGenericSettingsKeys(keys, parent, document) {
437
+ parent.append(...keys.sort((a, b) => a.name.localeCompare(b.name)).map(key => {
438
+ const element = document.createElement("key");
439
+ element.setAttribute("name", key.name);
440
+ writeCommonGenericSettingsItemProps(element, key);
441
+ if (key.encoding) {
442
+ element.setAttribute("encoding", key.encoding);
443
+ }
444
+ if (key.searchMethod) {
445
+ element.setAttribute("search-method", key.searchMethod);
446
+ }
447
+ writeGenericSettingsKeys(key.keys, element, document);
448
+ return element;
449
+ }));
450
+ }
451
+ function appendNamedElementsListToConfig(containerName, elements, config) {
452
+ const allElements = Object.entries(elements);
453
+ if (allElements.length) {
454
+ const containerElement = config.createElement(containerName);
455
+ config.documentElement.append(containerElement);
456
+ containerElement.append(...allElements
457
+ .sort(([fieldNameA], [fieldNameB]) => fieldNameA.localeCompare(fieldNameB))
458
+ .map(([_, element]) => element));
459
+ }
460
+ }
461
+ function writeCommonGenericSettingsItemProps(element, item) {
462
+ if (item.label) {
463
+ element.setAttribute("label", item.label);
464
+ }
465
+ if (item.type) {
466
+ element.setAttribute("type", item.type);
467
+ }
468
+ if (item.subType) {
469
+ element.setAttribute("sub-type", item.subType);
470
+ }
471
+ }
@@ -6,4 +6,7 @@ export type IndividualExternalDepConfig = string | {
6
6
  export type Externals = {
7
7
  [dep: string]: IndividualExternalDepConfig;
8
8
  };
9
- export declare function makeDependencyExtractionPlugin(externals: Externals | undefined, assumeGlobalizedPlauditLibraries: boolean): false | DependencyExtractionWebpackPlugin;
9
+ export declare function makeDependencyExtractionPlugin(externals: Externals | undefined, assumeGlobalizedPlauditLibraries: boolean, wantsGroupedDepData: boolean): {
10
+ instance: DependencyExtractionWebpackPlugin;
11
+ addExternalizedDep: (dep: string) => void;
12
+ };
@@ -5,15 +5,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeDependencyExtractionPlugin = makeDependencyExtractionPlugin;
7
7
  const dependency_extraction_webpack_plugin_1 = __importDefault(require("@wordpress/dependency-extraction-webpack-plugin"));
8
- function makeDependencyExtractionPlugin(externals, assumeGlobalizedPlauditLibraries) {
8
+ function makeDependencyExtractionPlugin(externals, assumeGlobalizedPlauditLibraries, wantsGroupedDepData) {
9
+ const baseProps = makeDependencyExtractionPluginProps(externals, assumeGlobalizedPlauditLibraries);
10
+ const instance = new dependency_extraction_webpack_plugin_1.default(wantsGroupedDepData ? { ...baseProps, outputFormat: "json", combineAssets: true } : baseProps);
11
+ return {
12
+ instance,
13
+ addExternalizedDep: (dep) => {
14
+ instance.externalizedDeps.add(dep);
15
+ }
16
+ };
17
+ }
18
+ function makeDependencyExtractionPluginProps(externals, assumeGlobalizedPlauditLibraries) {
9
19
  if (!externals) {
10
20
  if (assumeGlobalizedPlauditLibraries) {
11
- return new dependency_extraction_webpack_plugin_1.default({
21
+ return {
12
22
  requestToExternal: plauditRequestToExternal,
13
23
  requestToHandle: plauditRequestToHandle
14
- });
24
+ };
15
25
  }
16
- return false;
26
+ return {};
17
27
  }
18
28
  const exactExternals = {};
19
29
  const suffixExternals = [];
@@ -54,15 +64,18 @@ function makeDependencyExtractionPlugin(externals, assumeGlobalizedPlauditLibrar
54
64
  }
55
65
  return undefined;
56
66
  };
57
- return assumeGlobalizedPlauditLibraries
58
- ? new dependency_extraction_webpack_plugin_1.default({
67
+ if (assumeGlobalizedPlauditLibraries) {
68
+ return {
59
69
  requestToExternal: curryRequestHandlers(baselineRequestToExternal, plauditRequestToExternal),
60
70
  requestToHandle: curryRequestHandlers(baselineRequestToHandle, plauditRequestToHandle),
61
- })
62
- : new dependency_extraction_webpack_plugin_1.default({
71
+ };
72
+ }
73
+ else {
74
+ return {
63
75
  requestToExternal: baselineRequestToExternal,
64
76
  requestToHandle: baselineRequestToHandle,
65
- });
77
+ };
78
+ }
66
79
  }
67
80
  const PLAUDIT_NAMESPACE = '@plaudit/';
68
81
  const EXTERNALIZABLE_PLAUDIT_LIBRARIES = ['@plaudit/library-extensions'];
@@ -5,7 +5,7 @@ interface AdvancedOutputConfig {
5
5
  destination: string;
6
6
  withLegacyBlocksIn?: string | undefined;
7
7
  additionalDependencies?: string[];
8
- directoryLayout?: 'blocks' | 'extensions';
8
+ directoryLayout?: 'blocks' | 'extensions' | 'plain';
9
9
  assumeGlobalizedPlauditLibraries?: boolean;
10
10
  }
11
11
  type PlauditWordpressWebpackConfig = {
@@ -19,6 +19,8 @@ type PlauditWordpressWebpackConfig = {
19
19
  };
20
20
  externals?: Externals;
21
21
  assumeGlobalizedPlauditLibraries?: boolean;
22
+ processTranslationConfigs?: boolean;
23
+ combineAssetMetadata?: boolean;
22
24
  };
23
25
  declare const _default: (config: PlauditWordpressWebpackConfig, webpackConfig?: Configuration[] | Configuration) => Configuration[];
24
26
  export = _default;
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  const node_fs_1 = __importDefault(require("node:fs"));
6
+ const promises_1 = __importDefault(require("node:fs/promises"));
6
7
  const node_path_1 = __importDefault(require("node:path"));
7
8
  const AdditionalDependencyInjectorPlugin_1 = __importDefault(require("./wordpress-scripts-wrapper/AdditionalDependencyInjectorPlugin"));
8
9
  const BlockJSONManagingPlugin_1 = __importDefault(require("./wordpress-scripts-wrapper/BlockJSONManagingPlugin"));
@@ -12,6 +13,7 @@ const MiniCSSExtractPluginErrorCleaner_1 = __importDefault(require("./wordpress-
12
13
  const VariablesJSMonitorPlugin_1 = __importDefault(require("./wordpress-scripts-wrapper/VariablesJSMonitorPlugin"));
13
14
  const BrowserSyncPlugin_1 = require("./wordpress-scripts-wrapper/BrowserSyncPlugin");
14
15
  const static_configs_1 = require("./wordpress-scripts-wrapper/static-configs");
16
+ const WPMLConfigBuilder_1 = __importDefault(require("./wordpress-scripts-wrapper/WPMLConfigBuilder"));
15
17
  const dependency_extraction_webpack_plugin_1 = __importDefault(require("@wordpress/dependency-extraction-webpack-plugin"));
16
18
  const copy_webpack_plugin_1 = __importDefault(require("copy-webpack-plugin"));
17
19
  const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
@@ -246,7 +248,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
246
248
  scriptExtension = scriptWithoutModuleExtension;
247
249
  entrypointFields = ["editorStyle", "viewStyle", "style", "editorScript", "viewScript", "script"];
248
250
  }
249
- const { standaloneBlocks, variablesFilePath, verbose, externals, assumeGlobalizedPlauditLibraries } = config;
251
+ const { standaloneBlocks, variablesFilePath, verbose, externals, assumeGlobalizedPlauditLibraries, combineAssetMetadata } = config;
250
252
  let currentVariables = config.currentVariables;
251
253
  const fixedRules = [
252
254
  replaceDefaultURLProcessing,
@@ -255,6 +257,16 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
255
257
  },
256
258
  injectSupportForInliningSVGsAsStrings
257
259
  ].reduce((r, a) => a(r), webpackConfig.module?.rules ?? []);
260
+ if (config.processTranslationConfigs) {
261
+ fixedRules.push({
262
+ test: /wpml-config\.xml$/i,
263
+ type: 'asset/resource',
264
+ generator: {
265
+ filename: '[name][ext]',
266
+ emit: false
267
+ }
268
+ });
269
+ }
258
270
  return sources.map(([src, dest]) => {
259
271
  const srcRoots = (typeof dest !== 'string' && dest.withLegacyBlocksIn
260
272
  ? [...src.split(','), ...resolveLegacyBlockScriptsInFolder(dest.withLegacyBlocksIn)]
@@ -302,22 +314,26 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
302
314
  if (variablesFilePath) {
303
315
  plugins.push(new VariablesJSMonitorPlugin_1.default(variablesFilePath));
304
316
  }
305
- if (copyFiles && (typeof dest === 'string' || dest.directoryLayout !== 'extensions')) {
306
- plugins.push(new BlockJSONManagingPlugin_1.default(standaloneBlocks, processingModules));
307
- }
308
- plugins.push(new AdditionalDependencyInjectorPlugin_1.default(typeof dest !== 'string' && dest.additionalDependencies ? dest.additionalDependencies : [], processingModules));
309
- if (srcIsDirectory && (typeof dest !== 'string' && dest.directoryLayout === 'extensions')) {
310
- plugins.push(new ExtensionsConfigFileGeneratorPlugin_1.default(srcRoot));
317
+ const forBlocksDirectory = copyFiles && (typeof dest === 'string' || (dest.directoryLayout !== 'extensions' && dest.directoryLayout !== 'plain'));
318
+ if (forBlocksDirectory) {
319
+ const blockJSONManagingPlugin = new BlockJSONManagingPlugin_1.default(standaloneBlocks, processingModules);
320
+ plugins.push(blockJSONManagingPlugin);
321
+ if (config.processTranslationConfigs && srcIsDirectory && !processingModules) {
322
+ plugins.push(new WPMLConfigBuilder_1.default(blockJSONManagingPlugin));
323
+ }
311
324
  }
312
325
  const pluginIndex = plugins.findIndex(plugin => plugin instanceof dependency_extraction_webpack_plugin_1.default);
313
326
  if (pluginIndex === -1) {
314
327
  console.error("Cannot apply externals when they have been disabled via CLI flag. This will greatly increase bundle size and will likely cause the build to file");
315
328
  }
316
329
  else {
317
- const builtDependencyExtractionWebpackPlugin = (0, dependency_extraction_webpack_plugin_config_builder_1.makeDependencyExtractionPlugin)(externals, (typeof dest !== 'string' ? dest.assumeGlobalizedPlauditLibraries : undefined) ?? assumeGlobalizedPlauditLibraries);
318
- if (builtDependencyExtractionWebpackPlugin) {
319
- plugins[pluginIndex] = builtDependencyExtractionWebpackPlugin;
320
- }
330
+ const localAssumeGlobalizedPlauditLibraries = typeof dest !== 'string' ? dest.assumeGlobalizedPlauditLibraries : undefined;
331
+ const builtDependencyExtractionWebpackPlugin = (0, dependency_extraction_webpack_plugin_config_builder_1.makeDependencyExtractionPlugin)(externals, localAssumeGlobalizedPlauditLibraries ?? assumeGlobalizedPlauditLibraries, combineAssetMetadata && !processingModules && forBlocksDirectory);
332
+ plugins[pluginIndex] = builtDependencyExtractionWebpackPlugin.instance;
333
+ plugins.push(new AdditionalDependencyInjectorPlugin_1.default(typeof dest !== 'string' && dest.additionalDependencies ? dest.additionalDependencies : [], processingModules, builtDependencyExtractionWebpackPlugin.addExternalizedDep));
334
+ }
335
+ if (srcIsDirectory && (typeof dest !== 'string' && dest.directoryLayout === 'extensions')) {
336
+ plugins.push(new ExtensionsConfigFileGeneratorPlugin_1.default(srcRoot));
321
337
  }
322
338
  if (process.argv.includes('--browser-sync') || process.env['BROWSER_SYNC'] === 'true') {
323
339
  plugins.push(new BrowserSyncPlugin_1.BrowserSyncPlugin());
@@ -325,50 +341,69 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
325
341
  let entry;
326
342
  if (srcIsDirectory) {
327
343
  if (typeof dest !== 'string' && dest.directoryLayout === 'extensions') {
328
- entry = () => {
329
- const rawEntrypoints = node_fs_1.default.readdirSync(srcRoot, 'utf8')
330
- .map(file => joinPossiblyAbsolutePaths(srcRoot, file))
331
- .filter(file => (scriptExtension.test(file) || styleExtension.test(file)) && node_fs_1.default.statSync(file).isFile())
332
- .map((file) => [node_path_1.default.basename(file, node_path_1.default.extname(file)), file]);
344
+ entry = async () => {
345
+ const rawEntrypoints = [];
346
+ for await (const dirent of await promises_1.default.opendir(srcRoot)) {
347
+ if (dirent.isFile()) {
348
+ if (scriptExtension.test(dirent.name) || styleExtension.test(dirent.name)) {
349
+ const file = joinPossiblyAbsolutePaths(srcRoot, dirent.name);
350
+ rawEntrypoints.push([node_path_1.default.basename(file, node_path_1.default.extname(file)), file]);
351
+ }
352
+ }
353
+ }
333
354
  return Object.fromEntries(rawEntrypoints);
334
355
  };
335
356
  }
336
357
  else {
337
- entry = () => {
338
- const rawEntrypoints = node_fs_1.default.readdirSync(srcRoot, 'utf8')
339
- .map(dir => joinPossiblyAbsolutePaths(srcRoot, dir))
340
- .filter(dir => node_fs_1.default.statSync(dir).isDirectory())
341
- .flatMap(dir => {
342
- const res = [];
343
- try {
344
- const blockJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'block.json'), 'utf8'));
345
- const blockJSONChunkName = node_path_1.default.join(node_path_1.default.basename(dir), "block.json");
346
- for (const key of entrypointFields) {
347
- if (key in blockJSON) {
348
- res.push(...mapToRealEntrypoints(blockJSON[key], dir, ep => ep.startsWith("file:") ? ep.substring(5) : ep, blockJSONChunkName));
349
- }
350
- }
351
- BlockJSONManagingPlugin_1.default.recordBlockJSONAssetSourceDir(blockJSONChunkName, dir);
352
- return res;
358
+ entry = async () => {
359
+ const loadingEntrypoints = [];
360
+ for await (const dirent of await promises_1.default.opendir(srcRoot)) {
361
+ if (!dirent.isDirectory()) {
362
+ continue;
353
363
  }
354
- catch (e) {
364
+ const dir = joinPossiblyAbsolutePaths(srcRoot, dirent.name);
365
+ loadingEntrypoints.push(new Promise(async (resolve) => {
366
+ const rawEntrypoints = [];
367
+ const wpmlFiles = [];
355
368
  try {
356
- const packageJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'package.json'), 'utf8'));
357
- res.push(...mapToRealEntrypoints(packageJSON['main'], dir));
358
- res.push(...mapToRealEntrypoints(packageJSON['style'], dir));
369
+ const blockJSON = JSON.parse(await promises_1.default.readFile(node_path_1.default.join(dir, 'block.json'), 'utf8'));
370
+ const blockJSONChunkName = node_path_1.default.join(node_path_1.default.basename(dir), "block.json");
371
+ for (const key of entrypointFields) {
372
+ if (key in blockJSON) {
373
+ rawEntrypoints.push(...mapToRealEntrypoints(blockJSON[key], dir, ep => ep.startsWith("file:") ? ep.substring(5) : ep, blockJSONChunkName));
374
+ }
375
+ }
376
+ wpmlFiles.push(node_path_1.default.join(dir, 'block.json'));
377
+ BlockJSONManagingPlugin_1.default.recordBlockJSONAssetSourceDir(blockJSONChunkName, dir);
359
378
  }
360
379
  catch (e) {
361
380
  try {
362
- res.push(...parseEntrypointsJSON(dir));
381
+ const packageJSON = JSON.parse(await promises_1.default.readFile(node_path_1.default.join(dir, 'package.json'), 'utf8'));
382
+ rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['main'], dir));
383
+ rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['style'], dir));
363
384
  }
364
385
  catch (e) {
365
- // This just means that the directory doesn't contain any declared entrypoints.
386
+ try {
387
+ rawEntrypoints.push(...parseEntrypointsJSON(dir));
388
+ }
389
+ catch (e) {
390
+ // This just means that the directory doesn't contain any declared entrypoints.
391
+ }
366
392
  }
367
393
  }
368
- }
369
- return res;
370
- });
371
- const perAssetPathGroupedEntrypoints = groupEntrypointsByAssetFile(rawEntrypoints, e => e[0]);
394
+ try {
395
+ const wpmlFilePath = node_path_1.default.join(dir, "wpml-config.xml");
396
+ await promises_1.default.access(wpmlFilePath);
397
+ wpmlFiles.push(wpmlFilePath);
398
+ }
399
+ catch (e) {
400
+ // This just means that the file doesn't exist
401
+ }
402
+ resolve([rawEntrypoints, wpmlFiles]);
403
+ }));
404
+ }
405
+ const allEntrypoints = await Promise.all(loadingEntrypoints);
406
+ const perAssetPathGroupedEntrypoints = groupEntrypointsByAssetFile(allEntrypoints.flatMap(e => e[0]), e => e[0]);
372
407
  const currentEntry = {};
373
408
  for (const groupedEntrypoints of perAssetPathGroupedEntrypoints.values()) {
374
409
  if (groupedEntrypoints.length === 1 && groupedEntrypoints[0] !== undefined) {
@@ -387,6 +422,16 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
387
422
  BlockJSONManagingPlugin_1.default.recordRawDependency(entry.lazyDependent, key);
388
423
  }
389
424
  }
425
+ const wpmlEntrypointFiles = allEntrypoints.flatMap(e => e[1]);
426
+ try {
427
+ await promises_1.default.access(node_path_1.default.join(srcRoot, "wpml-config.xml"));
428
+ currentEntry["wpml-config.xml"] = { import: [node_path_1.default.join(srcRoot, "wpml-config.xml"), ...wpmlEntrypointFiles] };
429
+ }
430
+ catch (e) {
431
+ if (wpmlEntrypointFiles.length) {
432
+ currentEntry["wpml-config.xml"] = { import: wpmlEntrypointFiles };
433
+ }
434
+ }
390
435
  return currentEntry;
391
436
  };
392
437
  }
@@ -469,13 +514,13 @@ function processIndividualWebpackConfig(config, webpackConfig, sources) {
469
514
  }
470
515
  module.exports = function (config, webpackConfig = require("@wordpress/scripts/config/webpack.config")) {
471
516
  testForDuplicatedEntryPaths(config);
472
- const { standaloneBlocks = false, stats = 'errors-warnings', variables: rawVariables, verbose = process.argv.includes('--verbose') || process.env['VERBOSE'] === 'true', postcss = {}, externals, assumeGlobalizedPlauditLibraries = true } = config;
517
+ const { standaloneBlocks = false, stats = 'errors-warnings', variables: rawVariables, verbose = process.argv.includes('--verbose') || process.env['VERBOSE'] === 'true', postcss = {}, externals, assumeGlobalizedPlauditLibraries = true, processTranslationConfigs = true, combineAssetMetadata = true } = config;
473
518
  let variablesFilePath = undefined;
474
519
  const currentVariables = rawVariables ?? {};
475
520
  if (!rawVariables) {
476
521
  variablesFilePath = ["variables.js", "src/site/variables.js"].map(p => node_path_1.default.join(process.cwd(), p)).filter(p => node_fs_1.default.existsSync(p))[0];
477
522
  }
478
- const cfg = { currentVariables, postcss, standaloneBlocks, stats, variablesFilePath, verbose, externals, assumeGlobalizedPlauditLibraries };
523
+ const cfg = { currentVariables, postcss, standaloneBlocks, stats, variablesFilePath, verbose, externals, assumeGlobalizedPlauditLibraries, processTranslationConfigs, combineAssetMetadata };
479
524
  const sources = Array.isArray(config.src) ? config.src.map(s => [s, s]) : Object.entries(config.src);
480
525
  if (Array.isArray(webpackConfig)) {
481
526
  return webpackConfig.toSorted((a, b) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaudit/webpack-extensions",
3
- "version": "2.39.0",
3
+ "version": "2.41.0",
4
4
  "license": "UNLICENSED",
5
5
  "scripts": {
6
6
  "prepublishOnly": "rm -rf build && mkdir build && tsc",
@@ -21,8 +21,9 @@
21
21
  }
22
22
  },
23
23
  "devDependencies": {
24
+ "@plaudit/gutenberg-api-extensions": "^2.66.0",
24
25
  "@types/browser-sync-webpack-plugin": "^2.2.5",
25
- "@types/node": "^22.13.10",
26
+ "@types/node": "^22.13.13",
26
27
  "@types/postcss-functions": "^4.0.4",
27
28
  "@types/tapable": "^2.2.7",
28
29
  "@types/webpack": "^5.28.5",
@@ -42,7 +43,7 @@
42
43
  "autoprefixer": "^10.4.21",
43
44
  "browser-sync": "^3.0.3",
44
45
  "clean-webpack-plugin": "^4.0.0",
45
- "copy-webpack-plugin": "^12.0.2",
46
+ "copy-webpack-plugin": "^10.2.4",
46
47
  "cssnano": "^6.1.2",
47
48
  "eslint": "^8.57.1",
48
49
  "eslint-plugin-jsdoc": "^48.11.0",
@@ -69,7 +70,8 @@
69
70
  "react": "^18.3.1",
70
71
  "react-dom": "^18.3.1",
71
72
  "webpack": "^5.98.0",
72
- "webpack-remove-empty-scripts": "^1.0.4"
73
+ "webpack-remove-empty-scripts": "^1.0.4",
74
+ "xml-formatter": "^3.6.5"
73
75
  },
74
76
  "engines": {
75
77
  "node": ">=20"