@plaudit/webpack-extensions 3.2.2 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [3.4.0] - 2026-03-16
9
+ ### Added
10
+ - Support for a directory-based `extensions` layout
11
+ - This only applies to sites using extensions v2 and higher
12
+ - This comes from version `2.87.0`
13
+
14
+ ## [3.3.0] - 2026-03-16
15
+ ### Added
16
+ - A few helper methods for tools that reference this package and care about the entrypoint resolution logic
17
+
8
18
  ## [3.2.2] - 2026-03-16
9
19
  ### Changed
10
20
  - Exposed additional aspects of the entrypoint resolution logic to tools that reference this package
@@ -56,6 +66,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
56
66
  - Legacy PostCSS features that have been integrated into modern CSS
57
67
  - `@extends` support
58
68
 
69
+ ## [2.87.0] - 2026-03-16
70
+ ### Added
71
+ - Support for a directory-based `extensions` layout
72
+ - This only applies to sites using extensions v2 and higher
73
+
74
+ ### Internals
75
+ - Backported the features from `3.2.x` and `3.3.0`
76
+
59
77
  ## [2.86.0] - 2026-03-16
60
78
  ### Added
61
79
  - Support for `Location-Encoding Filenames`
package/USER-GUIDE.md CHANGED
@@ -501,8 +501,10 @@ This is used to associate additional assets with blocks that are not in control
501
501
  [Specially named files](#file-naming) in a single subdirectory of `src`
502
502
  ```
503
503
  src/extensions/
504
- ├── core-paragraph-view-script.ts
505
- └── core-paragraph-editor-style.pcss
504
+ ├─ core/paragraph/
505
+ │ ├─ view.ts
506
+ │ └─ editor.pcss
507
+ └─ plaudit/block-library/accordion/style.pcss
506
508
  ```
507
509
 
508
510
  #### File Naming
@@ -513,6 +515,9 @@ Filenames **must** follow the pattern: `{kebab-case-block-name}-{type}.{ext}`
513
515
  - `script-module`, `view-script-module`
514
516
  - `setup` (this allows for PHP code to be loaded only when certain blocks are enabled and is intended for use in plugins, not themes)
515
517
  - `ext` **must** be for a [supported file type](#supported-file-types) and **should** correspond with the extension type (basically, don't enqueue a `.css` file as a script)
518
+ - For convenience, everything before the `{type}` can be split into directories on the hyphens
519
+ - When using this format, the filenames must be [Location-Encoding Filenames](#location-encoding-filenames) or `setup.php`
520
+ - This is only available in extensions v2 and up
516
521
 
517
522
  #### Notes
518
523
  - In order to have a directory be treated as `extensions`, the config **must** include `directoryLayout: 'extensions'`
@@ -1,15 +1,19 @@
1
1
  import { AbstractBiPhasicGroupAndEntryPlugin, EntryProvider } from "./AbstractBiPhasicGroupAndEntryPlugin";
2
- import { ParsedAssetJsonProvider, VerifiedAdvancedOutputConfig } from "../shared";
2
+ import { MinimumViableMetadata, ParsedAssetJsonProvider, VerifiedAdvancedOutputConfig } from "../shared";
3
3
  import type { VerifiedPlauditWordpressWebpackConfig } from "../utils/common-config-helpers";
4
4
  import { Compilation, type Compiler } from "webpack";
5
- export declare class ExtensionsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAndEntryPlugin {
5
+ export type ExtensionConfigFileGeneratorMetadata = MinimumViableMetadata & {
6
+ extensionId: string;
7
+ };
8
+ export declare class ExtensionsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAndEntryPlugin<ExtensionConfigFileGeneratorMetadata> {
6
9
  private readonly extensionsSrcPath;
7
10
  private readonly dest;
8
11
  private static readonly semaphore;
9
12
  private setupFiles;
10
- constructor(config: VerifiedPlauditWordpressWebpackConfig, extensionsSrcPath: string, dest: VerifiedAdvancedOutputConfig, context: string, entry: EntryProvider);
13
+ constructor(config: VerifiedPlauditWordpressWebpackConfig, extensionsSrcPath: string, dest: VerifiedAdvancedOutputConfig, context: string, entry: EntryProvider<ExtensionConfigFileGeneratorMetadata>);
11
14
  get extensionsDestPath(): string;
12
15
  apply(compiler: Compiler): void;
16
+ private walkSubtreeForMetaInfo;
13
17
  private generateVersionThreeConfigFile;
14
18
  protected attachUniquePhase(compilation: Compilation): void;
15
19
  protected processAssets(compilation: Compilation, parsedAssetJsonProvider: ParsedAssetJsonProvider): void;
@@ -1,11 +1,41 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
5
35
  Object.defineProperty(exports, "__esModule", { value: true });
6
36
  exports.ExtensionsConfigFileGeneratorPlugin = void 0;
7
- const promises_1 = __importDefault(require("node:fs/promises"));
8
- const node_path_1 = __importDefault(require("node:path"));
37
+ const promises_1 = require("node:fs/promises");
38
+ const node_path_1 = __importStar(require("node:path"));
9
39
  const php_writer_1 = require("@plaudit/php-writer");
10
40
  const expressions_1 = require("@plaudit/php-writer/expressions");
11
41
  const AbstractBiPhasicGroupAndEntryPlugin_1 = require("./AbstractBiPhasicGroupAndEntryPlugin");
@@ -34,24 +64,49 @@ class ExtensionsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAndEntryP
34
64
  compilation.contextDependencies.add(this.extensionsSrcPath);
35
65
  }
36
66
  const emissionPromises = [];
37
- for await (const { name: setupFilePath } of await promises_1.default.opendir(this.extensionsSrcPath, { encoding: 'utf-8' })) {
67
+ for await (const { name: setupFilePath } of await (0, promises_1.opendir)(this.extensionsSrcPath, { encoding: 'utf-8' })) {
38
68
  if (setupFilePath.endsWith("-setup.php")) {
39
69
  const setupFileSourcePath = node_path_1.default.join(this.extensionsSrcPath, setupFilePath);
40
70
  compilation.fileDependencies.add(setupFileSourcePath);
41
- emissionPromises.push(promises_1.default.readFile(setupFileSourcePath).then(contents => {
71
+ emissionPromises.push((0, promises_1.readFile)(setupFileSourcePath).then(contents => {
42
72
  compilation.emitAsset(node_path_1.default.join(this.dest.destination, setupFilePath), new webpack_1.sources.RawSource(contents), { size: Buffer.byteLength(contents) });
43
73
  const blockSlug = /^(.+?)-setup.php$/i.exec(setupFilePath)?.[1];
44
74
  return [blockSlug, setupFilePath];
45
75
  }));
46
76
  }
47
77
  }
78
+ await this.walkSubtreeForMetaInfo(compilation, this.extensionsSrcPath, this.dest, [], emissionPromises);
48
79
  this.setupFiles = (await Promise.all(emissionPromises))
49
80
  .filter((item) => item[0] !== undefined).sort((a, b) => a[0].localeCompare(b[0]));
50
81
  });
51
82
  }
83
+ async walkSubtreeForMetaInfo(compilation, srcRoot, dest, parents, emissionPromises) {
84
+ if (!compilation.contextDependencies.has(srcRoot)) {
85
+ compilation.contextDependencies.add(srcRoot);
86
+ }
87
+ for await (const dirent of await (0, promises_1.opendir)(srcRoot)) {
88
+ if (dirent.name.startsWith("~")) {
89
+ continue;
90
+ }
91
+ if (dirent.isFile()) {
92
+ if (dirent.name === "setup.php") {
93
+ const setupFilePath = (0, node_path_1.join)(...parents, dirent.name);
94
+ const setupFileSourcePath = node_path_1.default.join(this.extensionsSrcPath, setupFilePath);
95
+ compilation.fileDependencies.add(setupFileSourcePath);
96
+ emissionPromises.push((0, promises_1.readFile)(setupFileSourcePath).then(contents => {
97
+ compilation.emitAsset(node_path_1.default.join(this.dest.destination, setupFilePath), new webpack_1.sources.RawSource(contents), { size: Buffer.byteLength(contents) });
98
+ return [parents.join("-") /* blockSlug */, setupFilePath];
99
+ }));
100
+ }
101
+ }
102
+ else if (dirent.isDirectory()) {
103
+ await this.walkSubtreeForMetaInfo(compilation, (0, node_path_1.join)(srcRoot, dirent.name), dest, [...parents, dirent.name], emissionPromises);
104
+ }
105
+ }
106
+ }
52
107
  generateVersionThreeConfigFile(compilation, relevantAssetData, setupFilePaths) {
53
108
  const handlePrefix = `${this.config.targetHandlePrefix}_block-extensions`;
54
- const regex = /^(.+?)-((?:editor-|view-|)(?:style|script|script-module))\.(?:css|m?js)$/i;
109
+ const regex = /^(.+?)-((?:editor-|view-|)(?:style|script|script-module))$/i;
55
110
  const blockExtensionsConfig = {
56
111
  metadata: { version: this.config.extensionsVersion }, scriptHandles: {}, scriptModuleHandles: {}, styleHandles: {}, blocks: {}, setupFiles: {}
57
112
  };
@@ -62,7 +117,7 @@ class ExtensionsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAndEntryP
62
117
  return [assetPath, entry[1]];
63
118
  });
64
119
  for (const [assetPath, assetData] of normalizedAssetData) {
65
- const match = regex.exec(assetPath);
120
+ const match = regex.exec(assetData.extensionId);
66
121
  if (!match) {
67
122
  continue;
68
123
  }
@@ -127,7 +182,16 @@ class ExtensionsConfigFileGeneratorPlugin extends AbstractBiPhasicGroupAndEntryP
127
182
  });
128
183
  }
129
184
  processAssets(compilation, parsedAssetJsonProvider) {
130
- const relevantAssetData = this.extractRelevantAssetData(compilation, parsedAssetJsonProvider);
185
+ const relevantAssetData = Object.fromEntries(this.getRelevantEntrypoints(compilation)
186
+ .map(({ entrypoint, metadata, srcPath }) => {
187
+ const providedData = parsedAssetJsonProvider(entrypoint, metadata);
188
+ if (providedData === undefined) {
189
+ compilation.errors.push((0, shared_1.newWebpackErrorForFile)(`assets.json did not contain information for ${srcPath}`, srcPath));
190
+ return undefined;
191
+ }
192
+ return [providedData.assetName, { ...providedData.assetData, extensionId: metadata.extensionId }];
193
+ })
194
+ .filter(item => item !== undefined));
131
195
  const staticallyLoadedEntrypoints = Object.keys(relevantAssetData);
132
196
  const generateLoader = (writer) => {
133
197
  writer.require(this.extensionsDestPath + "extensions-loader.php", { dirRelative: true, once: true });
@@ -5,4 +5,6 @@ export declare const enum SourceType {
5
5
  plain = "plain"
6
6
  }
7
7
  export declare function isSourceType(str: string): str is SourceType;
8
- export declare function resolveAllConfigLevelEntrypoints(config: PlauditWordpressWebpackConfig): [string, AdvancedOutputConfig][];
8
+ type Entrypoints = [string, AdvancedOutputConfig][];
9
+ export declare function resolveAllConfigLevelEntrypoints(config: PlauditWordpressWebpackConfig, projectRoot?: string): Record<'staticEntrypoints' | 'dynamicEntrypoints', Entrypoints>;
10
+ export {};
@@ -9,28 +9,35 @@ const path_query_and_related_helpers_1 = require("./path-query-and-related-helpe
9
9
  function isSourceType(str) {
10
10
  return str === "blocks" /* SourceType.blocks */ || str === "extensions" /* SourceType.extensions */ || str === "plain" /* SourceType.plain */;
11
11
  }
12
- function resolveAllConfigLevelEntrypoints(config) {
12
+ function resolveAllConfigLevelEntrypoints(config, projectRoot = process.cwd()) {
13
13
  const srcDir = config.srcDir ?? "";
14
14
  const normalizeSrcAndDestination = ([rawSrc, dest]) => {
15
15
  let [src, pathQueryParameters] = (0, path_query_and_related_helpers_1.unpackPotentiallyPrefixedFilePath)(rawSrc);
16
16
  if (srcDir) {
17
17
  src = (0, node_path_1.join)(srcDir, src);
18
18
  }
19
- src = (0, node_path_1.isAbsolute)(src) ? (0, node_path_1.relative)(process.cwd(), src) : src;
19
+ src = (0, node_path_1.isAbsolute)(src) ? (0, node_path_1.relative)(projectRoot, src) : src;
20
+ let resultObject;
20
21
  if (dest.destination !== undefined && (0, node_path_1.isAbsolute)(dest.destination)) {
21
- return [src, { ...dest, destination: (0, node_path_1.relative)(process.cwd(), dest.destination), pathQueryParameters }];
22
+ resultObject = { ...dest, destination: (0, node_path_1.relative)(projectRoot, dest.destination) };
22
23
  }
23
- return [src, { ...dest, pathQueryParameters }];
24
+ else {
25
+ resultObject = { ...dest };
26
+ }
27
+ return [src, pathQueryParameters ? { ...resultObject, pathQueryParameters } : resultObject];
24
28
  };
25
29
  if (Array.isArray(config.src)) {
26
- return config.src.map(s => normalizeSrcAndDestination([s, { destination: s }]));
30
+ return {
31
+ staticEntrypoints: config.src.map(s => normalizeSrcAndDestination([s, { destination: s }])),
32
+ dynamicEntrypoints: []
33
+ };
27
34
  }
28
35
  else {
29
36
  const configSrc = config.src ?? {};
30
37
  // We check for files with location-encoding filenames and add the pertinent ones to the sources
31
38
  const dynamicallyIncludedEntrypoints = [];
32
39
  if (srcDir) { // This will only work if we have a unified src root
33
- const dynamicallyIncludedEntrypointsRoot = (0, node_path_1.isAbsolute)(srcDir) ? srcDir : (0, node_path_1.join)(process.cwd(), srcDir);
40
+ const dynamicallyIncludedEntrypointsRoot = (0, node_path_1.isAbsolute)(srcDir) ? srcDir : (0, node_path_1.join)(projectRoot, srcDir);
34
41
  using dir = (0, node_fs_1.opendirSync)(dynamicallyIncludedEntrypointsRoot);
35
42
  for (let dirent; (dirent = dir.readSync()) !== null;) {
36
43
  if (dirent.name in configSrc || `./${dirent.name}` in configSrc) {
@@ -67,9 +74,11 @@ function resolveAllConfigLevelEntrypoints(config) {
67
74
  }
68
75
  }
69
76
  }
70
- return [...Object.entries(configSrc), ...dynamicallyIncludedEntrypoints]
71
- .map(([k, v]) => {
72
- return normalizeSrcAndDestination([k, typeof v === 'boolean' ? {} : (typeof v === 'string' ? { destination: v } : v)]);
73
- });
77
+ return {
78
+ staticEntrypoints: Object.entries(configSrc).map(([k, v]) => {
79
+ return normalizeSrcAndDestination([k, typeof v === 'boolean' ? {} : (typeof v === 'string' ? { destination: v } : v)]);
80
+ }),
81
+ dynamicEntrypoints: dynamicallyIncludedEntrypoints.map(normalizeSrcAndDestination)
82
+ };
74
83
  }
75
84
  }
@@ -6,9 +6,10 @@ export type ParsedLocationEncodingFilename = {
6
6
  register?: boolean | number;
7
7
  };
8
8
  flags: NormalizedEnqueuingControlFlags;
9
+ niceName?: string;
9
10
  };
10
11
  export declare function parseLocationEncodingFilename(filename: string): ParsedLocationEncodingFilename | undefined;
11
- export declare function parseLocationEncodingFilenameForBlock(filename: string): Omit<ParsedLocationEncodingFilename, 'locations'> & {
12
+ export declare function parseLocationEncodingFilenameForBlock(filename: string, errorBuilder?: (message: string, filename: string) => unknown): Omit<ParsedLocationEncodingFilename, 'locations'> & {
12
13
  locations: Pick<RealUsageLocations, 'clientEditor' | 'clientView'>;
13
14
  } | undefined;
14
15
  /**
@@ -19,13 +19,14 @@ function parseLocationEncodingFilename(filename) {
19
19
  const nameSegments = name.split("."); //Split always returns at least one string
20
20
  const typeOverrideMatch = /^(?<enqueuePosition>.+)-(?<typeOverride>script|style|script-module)$|^(?<typeOverride>script|style|script-module)$/.exec(nameSegments[0]);
21
21
  if (typeOverrideMatch) {
22
- nameSegments[0] = typeOverrideMatch.groups?.["enqueuePosition"] ?? "both"; // We override the first segment with the version without
22
+ nameSegments[0] = typeOverrideMatch.groups?.["enqueuePosition"] ?? "both"; // We override the first segment with the version without the type override
23
23
  type = typeOverrideMatch.groups?.["typeOverride"];
24
24
  }
25
25
  const inlinePattern = /^(?<inline>inline)(?:[-=](?<position>before|after))?$|^strategy[-=](?<inline>inline)(?:-(?<position>before|after))?$/;
26
26
  const strategyPattern = /^strategy[-=](?<strategy>eager|lazy|defer|async)$|^(?<strategy>lazy|eager)$/;
27
27
  const fetchpriorityPattern = /^fetchpriority[-=](auto|low|high)$/;
28
28
  const bothViewAndEditorLocationPattern = /^(?:client-)?(?<both>both)(?:[-=](?<priority>-?\d+))?$/;
29
+ let niceName = undefined;
29
30
  for (const segment of nameSegments) {
30
31
  const { locationName, priority } = extractLocationFromPropertyEncodingFilenameSegment(segment);
31
32
  if (locationName) {
@@ -67,6 +68,9 @@ function parseLocationEncodingFilename(filename) {
67
68
  flags.in_footer = false;
68
69
  break;
69
70
  default:
71
+ if (niceName === undefined) {
72
+ niceName = segment;
73
+ }
70
74
  break;
71
75
  }
72
76
  }
@@ -74,16 +78,16 @@ function parseLocationEncodingFilename(filename) {
74
78
  if (Object.values(locations).length === 0) {
75
79
  return undefined;
76
80
  }
77
- return { type, locations, flags };
81
+ return { type, locations, flags, niceName };
78
82
  }
79
- function parseLocationEncodingFilenameForBlock(filename) {
83
+ function parseLocationEncodingFilenameForBlock(filename, errorBuilder = shared_1.newWebpackErrorForFile) {
80
84
  const parsedFilename = parseLocationEncodingFilename(filename);
81
85
  if (parsedFilename !== undefined) {
82
86
  if ((0, shared_1.constantKeys)(parsedFilename.locations).some(value => value !== 'clientView' && value !== 'clientEditor')) {
83
- throw (0, shared_1.newWebpackErrorForFile)(`Block assets cannot be enqueued anywhere other than view, editor, or both. Saw: ${(0, shared_1.constantKeys)(parsedFilename).join(", ")}`, filename);
87
+ throw errorBuilder(`Block assets cannot be enqueued anywhere other than view, editor, or both. Saw: ${(0, shared_1.constantKeys)(parsedFilename).join(", ")}`, filename);
84
88
  }
85
89
  if (Object.values(parsedFilename.locations).some(value => typeof value === 'number')) {
86
- throw (0, shared_1.newWebpackErrorForFile)(`Block assets cannot be enqueued with a priority`, filename);
90
+ throw errorBuilder(`Block assets cannot be enqueued with a priority`, filename);
87
91
  }
88
92
  }
89
93
  return parsedFilename;
@@ -27,6 +27,7 @@ const UnifiedLoaderGenerator_1 = require("./plugins/UnifiedLoaderGenerator");
27
27
  const copy_webpack_plugin_1 = __importDefault(require("copy-webpack-plugin"));
28
28
  const fork_ts_checker_webpack_plugin_1 = __importDefault(require("fork-ts-checker-webpack-plugin"));
29
29
  const webpack_remove_empty_scripts_1 = __importDefault(require("webpack-remove-empty-scripts"));
30
+ const location_encoding_filename_parser_1 = require("./utils/location-encoding-filename-parser");
30
31
  function testForDuplicatedEntryPaths(sources) {
31
32
  const seenPaths = (0, common_config_helpers_1.groupEntrypointsByAssetFile)(Array.isArray(sources)
32
33
  ? sources.map(s => typeof s === 'string' ? s : s[1].destination)
@@ -191,7 +192,8 @@ function buildVerifiedConfig(config) {
191
192
  throw new Error("Plain Entrypoints V2 and higher require 'outputDir' to be set");
192
193
  }
193
194
  }
194
- const rawSources = (0, entrypoint_resolution_logic_1.resolveAllConfigLevelEntrypoints)(config);
195
+ const { staticEntrypoints, dynamicEntrypoints } = (0, entrypoint_resolution_logic_1.resolveAllConfigLevelEntrypoints)(config);
196
+ const rawSources = [...staticEntrypoints, ...dynamicEntrypoints];
195
197
  let variablesFilePath = undefined;
196
198
  const currentVariables = rawVariables ?? {};
197
199
  if (!rawVariables) {
@@ -505,12 +507,22 @@ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean
505
507
  const entry = async () => {
506
508
  const rawEntrypoints = [];
507
509
  for await (const dirent of await (0, promises_1.opendir)(srcRoot)) {
508
- if (dirent.isFile() && !dirent.name.startsWith("~")) {
509
- if (commonConfig.scriptExtension.test(dirent.name) || shared_1.styleExtension.test(dirent.name)) {
510
+ if (dirent.name.startsWith("~")) {
511
+ continue;
512
+ }
513
+ if (dirent.isFile()) {
514
+ if ((commonConfig.scriptExtension.test(dirent.name) || shared_1.styleExtension.test(dirent.name))) {
510
515
  const absoluteSrc = (0, common_config_helpers_1.joinPossiblyAbsolutePaths)(srcRoot, dirent.name);
511
- rawEntrypoints.push([(0, node_path_1.join)(dest.destination, (0, node_path_1.basename)(absoluteSrc, (0, node_path_1.extname)(absoluteSrc))), { import: [absoluteSrc], plauditMetadata: { dest, absoluteSrc } }]);
516
+ const extensionId = (0, node_path_1.parse)(dirent.name).name;
517
+ rawEntrypoints.push([(0, node_path_1.join)(dest.destination, (0, node_path_1.basename)(absoluteSrc, (0, node_path_1.extname)(absoluteSrc))), {
518
+ import: [absoluteSrc],
519
+ plauditMetadata: { dest, absoluteSrc, extensionId }
520
+ }]);
512
521
  }
513
522
  }
523
+ else if (dirent.isDirectory()) {
524
+ rawEntrypoints.push(...await walkExtensionsTree((0, node_path_1.join)(srcRoot, dirent.name), dest, [dirent.name]));
525
+ }
514
526
  }
515
527
  return Object.fromEntries(rawEntrypoints);
516
528
  };
@@ -551,7 +563,7 @@ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean
551
563
  if (canCopyFiles) {
552
564
  plugins.push(new copy_webpack_plugin_1.default({
553
565
  patterns: [{
554
- from: config.standaloneBlocks ? '**/*.(php|twig|svg)' : '**/*.(asset\.php|svg)',
566
+ from: config.standaloneBlocks ? '**/*.(php|twig|svg)' : '**/*.(asset\.php|svg)', //TODO: I'm pretty sure that the dots need proper escaping
555
567
  to: dest.destination,
556
568
  context: srcRoot /* canCopyFiles can only be true if srcRoot is a string, so this is safe */, noErrorOnMissing: true
557
569
  }]
@@ -562,6 +574,45 @@ function processIndividualWebpackConfig(config, webpackConfig, sources, canClean
562
574
  return (0, common_config_helpers_1.commonMakeWebpackConfig)(config, commonConfig, webpackConfig, externalize, plugins, canClean && batches.length < 2);
563
575
  }).filter(cfg => cfg !== undefined);
564
576
  }
577
+ async function walkExtensionsTree(srcRoot, dest, parents) {
578
+ const res = [];
579
+ for await (const dirent of await (0, promises_1.opendir)(srcRoot)) {
580
+ if (dirent.name.startsWith("~")) {
581
+ continue;
582
+ }
583
+ if (dirent.isFile()) {
584
+ const parsedFilename = (0, location_encoding_filename_parser_1.parseLocationEncodingFilename)(dirent.name);
585
+ if (parsedFilename === undefined) {
586
+ continue;
587
+ }
588
+ const absoluteSrc = (0, common_config_helpers_1.joinPossiblyAbsolutePaths)(srcRoot, dirent.name);
589
+ let destFile;
590
+ if (Object.keys(parsedFilename.locations).length === 1) {
591
+ if (parsedFilename.locations.clientView) {
592
+ destFile = `view-${parsedFilename.type}`;
593
+ }
594
+ else if (parsedFilename.locations.clientEditor) {
595
+ destFile = `editor-${parsedFilename.type}`;
596
+ }
597
+ else {
598
+ destFile = (0, node_path_1.basename)(absoluteSrc, (0, node_path_1.extname)(absoluteSrc));
599
+ }
600
+ }
601
+ else {
602
+ destFile = (0, node_path_1.basename)(absoluteSrc, (0, node_path_1.extname)(absoluteSrc));
603
+ }
604
+ const extensionId = parents.join("-") + "-" + destFile;
605
+ res.push([(0, node_path_1.join)(dest.destination, ...parents, destFile), {
606
+ import: [absoluteSrc],
607
+ plauditMetadata: { dest, absoluteSrc, extensionId }
608
+ }]);
609
+ }
610
+ else if (dirent.isDirectory()) {
611
+ res.push(...await walkExtensionsTree((0, node_path_1.join)(srcRoot, dirent.name), dest, [...parents, dirent.name]));
612
+ }
613
+ }
614
+ return res;
615
+ }
565
616
  function stripExtension(filepath) {
566
617
  return (0, node_path_1.join)((0, node_path_1.dirname)(filepath), (0, node_path_1.basename)(filepath, (0, node_path_1.extname)(filepath)));
567
618
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plaudit/webpack-extensions",
3
- "version": "3.2.2",
3
+ "version": "3.4.0",
4
4
  "license": "SEE LICENSE IN LICENSE.md",
5
5
  "files": [
6
6
  "/build",
@@ -11,6 +11,7 @@
11
11
  ],
12
12
  "exports": {
13
13
  "./wordpress-scripts-wrapper": "./build/wordpress-scripts-wrapper.js",
14
+ "./location-encoding-filename-parser": "./build/utils/location-encoding-filename-parser.js",
14
15
  "./shared": "./build/shared.js"
15
16
  },
16
17
  "typesVersions": {
@@ -18,6 +19,9 @@
18
19
  "wordpress-scripts-wrapper": [
19
20
  "build/wordpress-scripts-wrapper.d.ts"
20
21
  ],
22
+ "location-encoding-filename-parser": [
23
+ "build/location-encoding-filename-parser.d.ts"
24
+ ],
21
25
  "shared": [
22
26
  "build/shared.d.ts"
23
27
  ]