@plaudit/webpack-extensions 2.61.2 → 2.62.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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");
package/build/shared.d.ts CHANGED
@@ -1,5 +1,6 @@
1
+ import { PHPWriter } from "./utils/php-writer";
1
2
  import type { Options as PostcssFunctionsOptions } from "postcss-functions";
2
- import type { Configuration } from "webpack";
3
+ import { type Configuration, type EntryOptions, WebpackError } from "webpack";
3
4
  export type RawAssetData = Record<string, {
4
5
  dependencies: string[];
5
6
  version: string;
@@ -71,30 +72,45 @@ export type PlauditWordpressWebpackConfig = {
71
72
  srcPrefixes?: string[];
72
73
  useUnifiedLoader?: boolean;
73
74
  };
74
- export declare function makeEmittableConfigPHP(data: any): string;
75
- export type Sync<V> = {
76
- sync: Promise<V>;
77
- resolve(v: V): void;
78
- reject(): void;
79
- done: boolean;
80
- };
81
- type Readiness<V> = {
82
- nonModule: Sync<V>;
83
- module: Sync<V>;
75
+ export type SmuggledBlockEntrypointInfo = [
76
+ string,
77
+ EntrypointFields[number],
78
+ string,
79
+ string,
80
+ string
81
+ ];
82
+ export type UnpackedBlockEntrypointInfo = {
83
+ blockJsonOrigin: string;
84
+ entrypointField: EntrypointFields[number];
85
+ originalValue: string;
86
+ entrypointName: string;
87
+ handle: string;
84
88
  };
85
- export declare class SyncsManager<V> {
86
- private readonly readinessMapping;
87
- get(name: string): Readiness<V>;
88
- private makeSync;
89
- }
89
+ export declare function packBlockEntrypointInfoForSmuggling(info: UnpackedBlockEntrypointInfo): SmuggledBlockEntrypointInfo;
90
+ export declare function unpackSmuggledBlockEntrypointInfo(library: EntryOptions['library']): UnpackedBlockEntrypointInfo | undefined;
91
+ export declare function isSmuggledLibraryInfo(libraryName: NonNullable<EntryOptions['library']>['name'] | undefined): libraryName is SmuggledBlockEntrypointInfo;
92
+ export declare function makeEmittableConfigPHP(data: any, asFullFile: boolean, parentIndent?: string): string;
93
+ export type EntrypointFields = ["viewScriptModule", "scriptModule"] | ["editorStyle", "viewStyle", "style", "editorScript", "viewScript", "script"];
94
+ export declare const entrypointFields: ReadonlyArray<EntrypointFields[number]>;
95
+ export declare function convertEntrypointFieldForAssetType(entrypointField: EntrypointFields[number], assetType: 'script' | 'style'): EntrypointFields[number];
90
96
  export declare function leadingSlashIt(pathOrSomething: string): string;
91
97
  export declare const scriptExtension: RegExp;
92
98
  export declare const scriptWithoutModuleExtension: RegExp;
93
99
  export declare const scriptWithModuleExtension: RegExp;
94
100
  export declare const styleExtension: RegExp;
95
- export declare function scriptOrStyleTest(entryPath: string, scriptExtension: RegExp): "" | "script" | "style";
101
+ export declare function scriptOrStyleTest(entryPath: string, scriptExtension: RegExp): "" | "style" | "script";
102
+ export declare function isStyleField(field: string): boolean;
103
+ export declare function isScriptModuleField(field: string): boolean;
96
104
  export declare function hasAtLeastOneItem<T>(list: T[]): list is [T, ...T[]];
105
+ export type TupleOf<T, N extends number> = N extends N ? number extends N ? T[] : _TupleOf<T, N, []> : never;
106
+ type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N ? R : _TupleOf<T, N, [T, ...R]>;
107
+ export declare function arrayIsLength<T, N extends number>(arr: T[] | null | undefined, length: N): arr is TupleOf<T, N>;
97
108
  export declare function kebabCase(value: string): string;
98
109
  export declare function loadEnvFile(filePath: string): Promise<Record<string, string>>;
99
110
  export declare function parseEnvFile(contents: string): Record<string, string>;
111
+ export declare function newWebpackErrorForFile(error: string, file: string): WebpackError;
112
+ /**
113
+ * The primary benefit of emitting a function instead of baking its contents into each function that uses it is that it allows us to avoid recomputing the base uri multiple times
114
+ */
115
+ export declare function emitResolveBaseUriFunction(writer: PHPWriter): void;
100
116
  export {};
package/build/shared.js CHANGED
@@ -3,18 +3,29 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.styleExtension = exports.scriptWithModuleExtension = exports.scriptWithoutModuleExtension = exports.scriptExtension = exports.SyncsManager = exports.standardLocationNames = void 0;
6
+ exports.styleExtension = exports.scriptWithModuleExtension = exports.scriptWithoutModuleExtension = exports.scriptExtension = exports.entrypointFields = exports.standardLocationNames = void 0;
7
7
  exports.isRawAssetData = isRawAssetData;
8
8
  exports.determineCurrentSourceType = determineCurrentSourceType;
9
+ exports.packBlockEntrypointInfoForSmuggling = packBlockEntrypointInfoForSmuggling;
10
+ exports.unpackSmuggledBlockEntrypointInfo = unpackSmuggledBlockEntrypointInfo;
11
+ exports.isSmuggledLibraryInfo = isSmuggledLibraryInfo;
9
12
  exports.makeEmittableConfigPHP = makeEmittableConfigPHP;
13
+ exports.convertEntrypointFieldForAssetType = convertEntrypointFieldForAssetType;
10
14
  exports.leadingSlashIt = leadingSlashIt;
11
15
  exports.scriptOrStyleTest = scriptOrStyleTest;
16
+ exports.isStyleField = isStyleField;
17
+ exports.isScriptModuleField = isScriptModuleField;
12
18
  exports.hasAtLeastOneItem = hasAtLeastOneItem;
19
+ exports.arrayIsLength = arrayIsLength;
13
20
  exports.kebabCase = kebabCase;
14
21
  exports.loadEnvFile = loadEnvFile;
15
22
  exports.parseEnvFile = parseEnvFile;
16
- const json_to_php_but_with____injection_1 = __importDefault(require("./utils/json-to-php-but-with-__-injection"));
23
+ exports.newWebpackErrorForFile = newWebpackErrorForFile;
24
+ exports.emitResolveBaseUriFunction = emitResolveBaseUriFunction;
17
25
  const promises_1 = __importDefault(require("node:fs/promises"));
26
+ const json_to_php_but_with____injection_1 = __importDefault(require("./utils/json-to-php-but-with-__-injection"));
27
+ const php_writer_1 = require("./utils/php-writer");
28
+ const webpack_1 = require("webpack");
18
29
  function isRawAssetData(thing) {
19
30
  if (!thing || typeof thing !== 'object') {
20
31
  return false;
@@ -45,34 +56,37 @@ function determineCurrentSourceType(dest, srcIsDirectory) {
45
56
  return dest.directoryLayout;
46
57
  }
47
58
  }
48
- function makeEmittableConfigPHP(data) {
49
- return "<?php return "
50
- + json_to_php_but_with____injection_1.default.make({ indent: "\t", linebreak: "\n", shortArraySyntax: true })(data, "")
51
- .replaceAll(/(\n\t*)\[\s+],/gs, "$1[],")
52
- .replaceAll(/\[\n\t+([^\n]+)\n\t+]/gs, (_, inner) => `[${inner.trim()}]`)
53
- .replaceAll(/'rest' => \[\n\t+(\[(?:'[^']+')?]),\n\t+('[^']+')(?:,\n\t+(\[[^\n]+]))?\n\t+]/gs, (_, deps, hash, args) => `'rest' => [${[deps, hash, args].filter(value => !!value).join(", ")}]`)
54
- + ";";
55
- }
56
- class SyncsManager {
57
- readinessMapping = new Map();
58
- get(name) {
59
- const res = this.readinessMapping.get(name);
60
- if (res) {
61
- return res;
62
- }
63
- this.readinessMapping.set(name, { nonModule: this.makeSync(), module: this.makeSync() });
64
- return this.readinessMapping.get(name);
59
+ function packBlockEntrypointInfoForSmuggling(info) {
60
+ return [info.blockJsonOrigin, info.entrypointField, info.originalValue, info.entrypointName, info.handle];
61
+ }
62
+ function unpackSmuggledBlockEntrypointInfo(library) {
63
+ const libraryName = library?.name;
64
+ if (!isSmuggledLibraryInfo(libraryName)) {
65
+ return undefined;
65
66
  }
66
- makeSync() {
67
- const res = { done: false };
68
- res.sync = new Promise((resolve, reject) => {
69
- res.resolve = (v) => resolve(v);
70
- res.reject = () => reject();
71
- });
72
- return res;
67
+ return { blockJsonOrigin: libraryName[0], entrypointField: libraryName[1], originalValue: libraryName[2], entrypointName: libraryName[3], handle: libraryName[4] };
68
+ }
69
+ function isSmuggledLibraryInfo(libraryName) {
70
+ if (!Array.isArray(libraryName) || !arrayIsLength(libraryName, 5) || libraryName.some(item => typeof item !== 'string')) {
71
+ return false;
73
72
  }
73
+ return libraryName[0].endsWith("/block.json") && exports.entrypointFields.includes(libraryName[1]);
74
+ }
75
+ function makeEmittableConfigPHP(data, asFullFile, parentIndent = "") {
76
+ const prettyPrintedMetadata = json_to_php_but_with____injection_1.default.make({ indent: "\t", linebreak: "\n", shortArraySyntax: true })(data, parentIndent)
77
+ .replaceAll(/(\n\t*)\[\s+],/gs, "$1[],")
78
+ .replaceAll(/\[\n\t+([^\n]+)\n\t+]/gs, (_, inner) => `[${inner.trim()}]`)
79
+ .replaceAll(/'rest' => \[\n\t+(\[(?:'[^']+')?]),\n\t+('[^']+')(?:,\n\t+(\[[^\n]+]))?\n\t+]/gs, (_, deps, hash, args) => `'rest' => [${[deps, hash, args].filter(value => !!value).join(", ")}]`);
80
+ return asFullFile ? `<?php return ${prettyPrintedMetadata};` : prettyPrintedMetadata.trim();
81
+ }
82
+ exports.entrypointFields = [
83
+ "editorStyle", "viewStyle", "style", "editorScript", "viewScript", "script", "viewScriptModule", "scriptModule"
84
+ ];
85
+ function convertEntrypointFieldForAssetType(entrypointField, assetType) {
86
+ // Using these word fragments instead of the full words allows us to avoid having to deal with the capitalization of the first letter
87
+ const searchRep = assetType === 'script' ? ['tyle', 'cript'] : ['cript', 'tyle'];
88
+ return entrypointField.replace(...searchRep);
74
89
  }
75
- exports.SyncsManager = SyncsManager;
76
90
  function leadingSlashIt(pathOrSomething) {
77
91
  return pathOrSomething.startsWith('/') ? pathOrSomething : ('/' + pathOrSomething);
78
92
  }
@@ -83,9 +97,18 @@ exports.styleExtension = /(?<filename>.+)(?<extension>\.(p?c|sa)ss)$/i;
83
97
  function scriptOrStyleTest(entryPath, scriptExtension) {
84
98
  return scriptExtension.test(entryPath) ? "script" : (exports.styleExtension.test(entryPath) ? "style" : "");
85
99
  }
100
+ function isStyleField(field) {
101
+ return field.endsWith("tyle");
102
+ }
103
+ function isScriptModuleField(field) {
104
+ return field.includes("odule");
105
+ }
86
106
  function hasAtLeastOneItem(list) {
87
107
  return list.length > 0;
88
108
  }
109
+ function arrayIsLength(arr, length) {
110
+ return !!arr && arr.length === length;
111
+ }
89
112
  function kebabCase(value) {
90
113
  const kebabCaseRegexes = [[/([a-z])([A-Z])/g, "$1-$2"], [/[\s_.\-]+/g, "-"]];
91
114
  return kebabCaseRegexes.reduce((str, [pattern, replacement]) => str.replace(pattern, replacement), value).toLowerCase();
@@ -101,3 +124,33 @@ function parseEnvFile(contents) {
101
124
  return equalsPos === -1 ? [line, ""] : [line.substring(0, equalsPos), line.substring(equalsPos + 1)];
102
125
  }));
103
126
  }
127
+ function newWebpackErrorForFile(error, file) {
128
+ const res = new webpack_1.WebpackError(error);
129
+ res.hideStack = true;
130
+ res.file = file;
131
+ return res;
132
+ }
133
+ /**
134
+ * The primary benefit of emitting a function instead of baking its contents into each function that uses it is that it allows us to avoid recomputing the base uri multiple times
135
+ */
136
+ function emitResolveBaseUriFunction(writer) {
137
+ const dir = new php_writer_1.Var("dir");
138
+ const baseUris = new php_writer_1.Var("base_uris");
139
+ const assignmentTarget = new php_writer_1.ArrayAccess(baseUris, dir);
140
+ const path = new php_writer_1.Var("path");
141
+ writer.function("plaudit_webpack_extensions__resolve_base_uri", [dir], writer => {
142
+ writer
143
+ .static(baseUris, { initializer: [] })
144
+ .if(php_writer_1.Expr.isset(assignmentTarget))
145
+ .return(assignmentTarget)
146
+ .elseIf(php_writer_1.Expr.call("str_starts_with", [dir, php_writer_1.Constants.ABSPATH]))
147
+ .assign(path, php_writer_1.Expr.call("ltrim", [php_writer_1.Expr.call("substr", [dir, php_writer_1.Expr.call("strlen", [php_writer_1.Constants.ABSPATH])]), "/"]))
148
+ .elseIf(php_writer_1.Expr.call("str_starts_with", [dir, "/workspace/website"]))
149
+ .assign(path, php_writer_1.Expr.call("ltrim", [php_writer_1.Expr.call("substr", [dir, 18]), "/"]))
150
+ .else()
151
+ .call("error_log", ["UNABLE TO FIGURE OUT WHAT THE RELATIVE PATH TO THE BUILT FILES DIRECTORY SHOULD BE"])
152
+ .assign(path, "")
153
+ .endIf()
154
+ .call("trailingslashit", [php_writer_1.Expr.call("home_url", [path])], { return: true, assignTo: assignmentTarget });
155
+ }, { returnType: "string", includeExistenceCheck: true });
156
+ }
@@ -1,4 +1,4 @@
1
- import { PlauditWordpressWebpackConfig, VerifiedAdvancedOutputConfig } from "../shared";
1
+ import { EntrypointFields, PlauditWordpressWebpackConfig, VerifiedAdvancedOutputConfig } from "../shared";
2
2
  import type { Compiler, Configuration, EntryObject, WebpackPluginInstance } from "webpack";
3
3
  import type WebpackRemoveEmptyScriptsPlugin from "webpack-remove-empty-scripts";
4
4
  export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpressWebpackConfig, 'variables' | 'src' | 'externals'>> & {
@@ -10,7 +10,7 @@ export type CommonPluginConfig = {
10
10
  removeEmptyScriptsPlugin: WebpackRemoveEmptyScriptsPlugin;
11
11
  };
12
12
  export type CommonConfigProcessingResult = {
13
- entrypointFields: string[];
13
+ entrypointFields: EntrypointFields;
14
14
  fixedRules: NonNullable<Configuration['module']>['rules'];
15
15
  processingModules: boolean;
16
16
  scriptExtension: RegExp;
@@ -10,7 +10,6 @@ exports.commonMakeWebpackConfig = commonMakeWebpackConfig;
10
10
  const node_fs_1 = __importDefault(require("node:fs"));
11
11
  const promises_1 = __importDefault(require("node:fs/promises"));
12
12
  const node_path_1 = __importDefault(require("node:path"));
13
- const BlockJSONManagingPlugin_1 = require("../plugins/BlockJSONManagingPlugin");
14
13
  const shared_1 = require("../shared");
15
14
  const copy_webpack_plugin_1 = __importDefault(require("copy-webpack-plugin"));
16
15
  let isInThemeCache = undefined;
@@ -34,20 +33,20 @@ function groupEntrypointsByAssetFile(entrypoints, entrypointNameExtractor) {
34
33
  }
35
34
  return seenPaths;
36
35
  }
37
- function mapToRealEntrypoints(entrypoint, dir, args = {}) {
38
- const { mapper = ep => ep, lazyDependent, associatedQuery, destDir } = args;
36
+ function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args = {}) {
37
+ const { mapper = ep => ep, destDir } = args;
39
38
  return (Array.isArray(entrypoint) ? entrypoint : [entrypoint])
40
39
  .map(ep => joinPossiblyAbsolutePaths(dir, mapper(ep)))
41
- .filter(ep => node_fs_1.default.statSync(ep, { throwIfNoEntry: false })?.isFile())
40
+ .filter(ep => supportedExtensions(ep) && node_fs_1.default.statSync(ep, { throwIfNoEntry: false })?.isFile())
42
41
  .map(ep => {
43
42
  const parsedEntrypoint = node_path_1.default.parse(ep);
44
- return [joinPossiblyAbsolutePaths(destDir, node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name), { import: ep, lazyDependent, associatedQuery }];
43
+ return [joinPossiblyAbsolutePaths(destDir, node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name), { import: ep }];
45
44
  });
46
45
  }
47
- function parseEntrypointsJSON(dir, dest) {
46
+ function parseEntrypointsJSON(dir, dest, supportedExtensions) {
48
47
  const entrypointsJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'entrypoints.json'), 'utf8'));
49
48
  if (Array.isArray(entrypointsJSON)) {
50
- return mapToRealEntrypoints(entrypointsJSON, dir, { destDir: dest.destination });
49
+ return mapToRealEntrypoints(entrypointsJSON, dir, supportedExtensions, { destDir: dest.destination });
51
50
  }
52
51
  else {
53
52
  return Object.entries(entrypointsJSON).map(([name, config]) => {
@@ -115,31 +114,95 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
115
114
  if (!dirent.isDirectory()) {
116
115
  continue;
117
116
  }
118
- //TODO: Instead of doing all of this in a precalc phase, add block.json "entrypoints" with their library type set to "block-json"
117
+ //TODO: It should be possible to handle all block.json files simultaneously, which would allow for better detection of repeated code
119
118
  const dir = joinPossiblyAbsolutePaths(srcRoot, dirent.name);
120
119
  loadingEntrypoints.push(new Promise(async (resolve) => {
121
120
  const rawEntrypoints = [];
122
121
  const wpmlFiles = [];
123
122
  try {
124
- const blockJSON = JSON.parse(await promises_1.default.readFile(node_path_1.default.join(dir, 'block.json'), 'utf8'));
125
- const blockJSONChunkName = node_path_1.default.join(dest.destination, node_path_1.default.relative(srcRoot, dir), "block.json");
126
- for (const key of entrypointFields) {
127
- if (key in blockJSON) {
128
- rawEntrypoints.push(...mapToRealEntrypoints(blockJSON[key], dir, { mapper: ep => ep.startsWith("file:") ? ep.substring(5) : ep, lazyDependent: blockJSONChunkName, destDir: dest.destination }));
123
+ const blockJsonOrigin = node_path_1.default.join(dir, 'block.json');
124
+ const blockJson = JSON.parse(await promises_1.default.readFile(blockJsonOrigin, 'utf8'));
125
+ const blockJsonChunkName = node_path_1.default.join(dest.destination, node_path_1.default.relative(srcRoot, dir), "block");
126
+ const presentEntrypoints = (await Promise.all(entrypointFields
127
+ .filter(entrypointField => entrypointField in blockJson)
128
+ .flatMap(entrypointField => {
129
+ return (Array.isArray(blockJson[entrypointField]) ? blockJson[entrypointField] : [blockJson[entrypointField]])
130
+ .filter(originalValue => originalValue.startsWith("file:"))
131
+ .map(originalValue => {
132
+ const entrypointPath = originalValue.substring(5);
133
+ const absoluteSrc = node_path_1.default.normalize(node_path_1.default.join(dir, entrypointPath));
134
+ return promises_1.default.stat(absoluteSrc)
135
+ .then(stats => {
136
+ if (stats.isFile()) {
137
+ const parsedEntrypoint = node_path_1.default.parse(node_path_1.default.normalize(node_path_1.default.join(dest.destination, node_path_1.default.relative(srcRoot, dir), entrypointPath)));
138
+ const extensionlessExpectedSrc = node_path_1.default.normalize(node_path_1.default.join(parsedEntrypoint.dir, parsedEntrypoint.name));
139
+ const entrypointName = node_path_1.default.normalize(joinPossiblyAbsolutePaths(parsedEntrypoint.dir, parsedEntrypoint.name));
140
+ return { entrypointField, originalValue, entrypointName, extensionlessExpectedSrc, absoluteSrc };
141
+ }
142
+ else {
143
+ return undefined;
144
+ }
145
+ }, () => undefined);
146
+ });
147
+ }))).filter(pe => pe !== undefined);
148
+ const entrypointNamesWithEffectiveDuplicates = presentEntrypoints
149
+ .map(entry => entry.entrypointName)
150
+ .reduce((a, dest) => {
151
+ // If it's undefined, then this is the first instance, otherwise, it's not the first instance and, therefore, is expected to be a duplicate
152
+ a[dest] = (a[dest] !== undefined);
153
+ return a;
154
+ }, {});
155
+ const handlePrefix = blockJson['name']?.toString() ?? `__UNKNOWN_PREFIX__/${dirent.name}`;
156
+ const allocatedDestinations = {};
157
+ const resolvedBlockEntrypoints = presentEntrypoints
158
+ .map(presentEntrypoint => {
159
+ const overallSource = node_path_1.default.dirname(blockJsonOrigin);
160
+ const overallSourceRelativeName = node_path_1.default.relative(overallSource, node_path_1.default.normalize(node_path_1.default.join(blockJsonOrigin, node_path_1.default.relative(overallSource, presentEntrypoint.extensionlessExpectedSrc))));
161
+ if (!entrypointNamesWithEffectiveDuplicates[presentEntrypoint.entrypointName]) {
162
+ return { blockJsonOrigin, ...presentEntrypoint, handle: `${handlePrefix}/${overallSourceRelativeName}` };
129
163
  }
130
- }
164
+ const baseSuffix = `_${(0, shared_1.isStyleField)(presentEntrypoint.entrypointField) ? "style" : "script"}`;
165
+ let count = 0, suffix = baseSuffix, deduplicatedEntrypointName;
166
+ while (((deduplicatedEntrypointName = (presentEntrypoint.entrypointName + suffix)) in allocatedDestinations)
167
+ && allocatedDestinations[deduplicatedEntrypointName] !== presentEntrypoint.originalValue) {
168
+ suffix = baseSuffix + "_" + (++count);
169
+ }
170
+ allocatedDestinations[deduplicatedEntrypointName] = presentEntrypoint.originalValue;
171
+ const deduplicatedExtensionlessExpectedSrc = presentEntrypoint.extensionlessExpectedSrc + suffix;
172
+ return {
173
+ blockJsonOrigin,
174
+ ...presentEntrypoint,
175
+ entrypointName: deduplicatedEntrypointName,
176
+ extensionlessExpectedSrc: deduplicatedExtensionlessExpectedSrc,
177
+ handle: `${handlePrefix}/${count ? overallSourceRelativeName + "_" + count : overallSourceRelativeName}`
178
+ };
179
+ });
180
+ rawEntrypoints.push(...resolvedBlockEntrypoints
181
+ .map(resolvedBlockEntrypoint => {
182
+ return [
183
+ resolvedBlockEntrypoint.entrypointName,
184
+ {
185
+ import: resolvedBlockEntrypoint.absoluteSrc,
186
+ library: { name: (0, shared_1.packBlockEntrypointInfoForSmuggling)(resolvedBlockEntrypoint), type: `block-json-${dest.destination}` }
187
+ }
188
+ ];
189
+ }));
190
+ rawEntrypoints.push([blockJsonChunkName, { import: blockJsonOrigin, library: { name: "block-json-inclusion-assurance", type: `block-json-${dest.destination}` } }]);
131
191
  wpmlFiles.push(node_path_1.default.join(dir, 'block.json'));
132
- BlockJSONManagingPlugin_1.BlockJSONManagingPlugin.recordBlockJSONAssetSourceDir(blockJSONChunkName, dir);
133
192
  }
134
193
  catch (e) {
135
194
  try {
136
195
  const packageJSON = JSON.parse(await promises_1.default.readFile(node_path_1.default.join(dir, 'package.json'), 'utf8'));
137
- rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['main'], dir, { destDir: dest.destination }));
138
- rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['style'], dir, { destDir: dest.destination }));
196
+ if (packageJSON['main']) {
197
+ rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['main'], dir, commonConfig.scriptExtension.test, { destDir: dest.destination }));
198
+ }
199
+ if (!processingModules && packageJSON['style']) {
200
+ rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['style'], dir, shared_1.styleExtension.test, { destDir: dest.destination }));
201
+ }
139
202
  }
140
203
  catch (e) {
141
204
  try {
142
- rawEntrypoints.push(...parseEntrypointsJSON(dir, dest));
205
+ rawEntrypoints.push(...parseEntrypointsJSON(dir, dest, ep => commonConfig.scriptExtension.test(ep) || shared_1.styleExtension.test(ep)));
143
206
  }
144
207
  catch (e) {
145
208
  // This just means that the directory doesn't contain any declared entrypoints.
@@ -173,22 +236,16 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
173
236
  }
174
237
  }
175
238
  }
176
- // This is used to allow for block.json dependencies to correctly account for name-deduplication
177
- for (const [key, entry] of Object.entries(currentEntry)) {
178
- if (typeof entry === 'object' && !Array.isArray(entry) && 'lazyDependent' in entry && typeof entry.lazyDependent === 'string') {
179
- BlockJSONManagingPlugin_1.BlockJSONManagingPlugin.recordRawDependency(entry.lazyDependent, key);
180
- }
181
- }
182
239
  if (!processingModules) {
183
240
  const wpmlEntrypointFiles = allEntrypoints.flatMap(e => e[1]);
184
241
  try {
185
242
  await promises_1.default.access(node_path_1.default.join(srcRoot, "wpml-config.xml"));
186
- currentEntry["wpml-config.xml"] = { import: [node_path_1.default.join(srcRoot, "wpml-config.xml"), ...wpmlEntrypointFiles] };
243
+ currentEntry["wpml-config.xml"] = { import: [node_path_1.default.join(srcRoot, "wpml-config.xml"), ...wpmlEntrypointFiles], library: { type: `block-json-${dest.destination}` } };
187
244
  }
188
245
  catch (e) {
189
246
  // If the wpml-config.xml file does not exist, just "import" the other files that will be used to build the emitted version
190
247
  if (wpmlEntrypointFiles.length) {
191
- currentEntry["wpml-config.xml"] = { import: wpmlEntrypointFiles };
248
+ currentEntry["wpml-config.xml"] = { import: wpmlEntrypointFiles, library: { type: `block-json-${dest.destination}` } };
192
249
  }
193
250
  }
194
251
  }
@@ -260,7 +317,7 @@ function commonMakeWebpackConfig(config, commonConfig, webpackConfig, srcIsDirec
260
317
  .map(plugin => !processingModules && plugin.constructor.name === 'CopyPlugin'
261
318
  ? new copy_webpack_plugin_1.default({
262
319
  patterns: [{
263
- from: standaloneBlocks ? '**/(block.json|*.(php|twig|svg))' : '**/(block.json|*.(asset\.php|svg))',
320
+ from: standaloneBlocks ? '**/*.(php|twig|svg)' : '**/*.(asset\.php|svg)',
264
321
  to: dest.destination,
265
322
  context: srcRoot /* canCopyFiles can only be true if srcRoot is a string, so this is safe */, noErrorOnMissing: true
266
323
  }]