@plaudit/webpack-extensions 2.62.3 → 2.63.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.
package/build/shared.d.ts CHANGED
@@ -20,7 +20,7 @@ export type UsageLocations = {
20
20
  [K in StandardLocationNames]?: boolean | number;
21
21
  } & {
22
22
  register?: boolean | number;
23
- handle?: string;
23
+ handle?: string | ((generatedHandle: string) => string);
24
24
  registerScriptArgs?: {
25
25
  strategy?: 'defer' | 'async';
26
26
  in_footer?: boolean;
@@ -47,9 +47,11 @@ export type AdvancedOutputConfig = {
47
47
  assumeGlobalizedPlauditLibraries?: boolean;
48
48
  externalize?: Required<Configuration>['output']['library'];
49
49
  bundleAnalyzer?: boolean;
50
- locations?: UsageLocations | string;
50
+ locations?: UsageLocations | UsageLocations['handle'];
51
+ };
52
+ export type VerifiedAdvancedOutputConfig = Omit<AdvancedOutputConfig, 'destination' | 'locations'> & Required<Pick<AdvancedOutputConfig, 'destination'>> & {
53
+ locations: UsageLocations;
51
54
  };
52
- export type VerifiedAdvancedOutputConfig = Omit<AdvancedOutputConfig, 'destination'> & Required<Pick<AdvancedOutputConfig, 'destination'>>;
53
55
  export type PlauditWordpressWebpackConfig = {
54
56
  standaloneBlocks?: boolean;
55
57
  variables?: Record<string, any>;
@@ -87,8 +89,9 @@ export type UnpackedBlockEntrypointInfo = {
87
89
  handle: string;
88
90
  };
89
91
  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 unpackSmuggledBlockEntrypointInfo(library: EntryOptions['library'], allowedEndings?: string[] | false): UnpackedBlockEntrypointInfo | undefined;
93
+ export declare function isSmuggledLibraryInfo(libraryName: NonNullable<EntryOptions['library']>['name'] | undefined, allowedEndings?: string[] | false): libraryName is SmuggledBlockEntrypointInfo;
94
+ export declare function convertUsageLocationsHandleToEmittableHandle(handle: UsageLocations['handle'], generatedHandle: string): string;
92
95
  export declare function makeEmittableConfigPHP(data: any, asFullFile: boolean, parentIndent?: string): string;
93
96
  export type EntrypointFields = ["viewScriptModule", "scriptModule"] | ["editorStyle", "viewStyle", "style", "editorScript", "viewScript", "script"];
94
97
  export declare const entrypointFields: ReadonlyArray<EntrypointFields[number]>;
@@ -108,7 +111,7 @@ export declare function arrayIsLength<T, N extends number>(arr: T[] | null | und
108
111
  export declare function kebabCase(value: string): string;
109
112
  export declare function loadEnvFile(filePath: string): Promise<Record<string, string>>;
110
113
  export declare function parseEnvFile(contents: string): Record<string, string>;
111
- export declare function newWebpackErrorForFile(error: string, file: string): WebpackError;
114
+ export declare function newWebpackErrorForFile(error: string | ConstructorParameters<typeof WebpackError>, file: string): WebpackError;
112
115
  /**
113
116
  * 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
117
  */
package/build/shared.js CHANGED
@@ -9,6 +9,7 @@ exports.determineCurrentSourceType = determineCurrentSourceType;
9
9
  exports.packBlockEntrypointInfoForSmuggling = packBlockEntrypointInfoForSmuggling;
10
10
  exports.unpackSmuggledBlockEntrypointInfo = unpackSmuggledBlockEntrypointInfo;
11
11
  exports.isSmuggledLibraryInfo = isSmuggledLibraryInfo;
12
+ exports.convertUsageLocationsHandleToEmittableHandle = convertUsageLocationsHandleToEmittableHandle;
12
13
  exports.makeEmittableConfigPHP = makeEmittableConfigPHP;
13
14
  exports.convertEntrypointFieldForAssetType = convertEntrypointFieldForAssetType;
14
15
  exports.leadingSlashIt = leadingSlashIt;
@@ -59,18 +60,23 @@ function determineCurrentSourceType(dest, srcIsDirectory) {
59
60
  function packBlockEntrypointInfoForSmuggling(info) {
60
61
  return [info.blockJsonOrigin, info.entrypointField, info.originalValue, info.entrypointName, info.handle];
61
62
  }
62
- function unpackSmuggledBlockEntrypointInfo(library) {
63
+ const defaultAllowedEndings = ["/block.json", "/entrypoints.json", "/package.json"];
64
+ function unpackSmuggledBlockEntrypointInfo(library, allowedEndings) {
63
65
  const libraryName = library?.name;
64
- if (!isSmuggledLibraryInfo(libraryName)) {
66
+ if (!isSmuggledLibraryInfo(libraryName, allowedEndings)) {
65
67
  return undefined;
66
68
  }
67
69
  return { blockJsonOrigin: libraryName[0], entrypointField: libraryName[1], originalValue: libraryName[2], entrypointName: libraryName[3], handle: libraryName[4] };
68
70
  }
69
- function isSmuggledLibraryInfo(libraryName) {
71
+ function isSmuggledLibraryInfo(libraryName, allowedEndings = defaultAllowedEndings) {
70
72
  if (!Array.isArray(libraryName) || !arrayIsLength(libraryName, 5) || libraryName.some(item => typeof item !== 'string')) {
71
73
  return false;
72
74
  }
73
- return libraryName[0].endsWith("/block.json") && exports.entrypointFields.includes(libraryName[1]);
75
+ return (!allowedEndings || allowedEndings.some(s => libraryName[0].endsWith(s))) && exports.entrypointFields.includes(libraryName[1]);
76
+ }
77
+ function convertUsageLocationsHandleToEmittableHandle(handle, generatedHandle) {
78
+ const emittableHandle = typeof handle === 'string' ? handle : handle?.(generatedHandle) ?? generatedHandle;
79
+ return emittableHandle.replaceAll("{basename}", generatedHandle);
74
80
  }
75
81
  function makeEmittableConfigPHP(data, asFullFile, parentIndent = "") {
76
82
  const prettyPrintedMetadata = json_to_php_but_with____injection_1.default.make({ indent: "\t", linebreak: "\n", shortArraySyntax: true })(data, parentIndent)
@@ -125,7 +131,7 @@ function parseEnvFile(contents) {
125
131
  }));
126
132
  }
127
133
  function newWebpackErrorForFile(error, file) {
128
- const res = new webpack_1.WebpackError(error);
134
+ const res = typeof error === 'string' ? new webpack_1.WebpackError(error) : new webpack_1.WebpackError(...error);
129
135
  res.hideStack = true;
130
136
  res.file = file;
131
137
  return res;
@@ -1,5 +1,6 @@
1
- import { EntrypointFields, PlauditWordpressWebpackConfig, VerifiedAdvancedOutputConfig } from "../shared";
2
- import type { Compiler, Configuration, EntryObject, WebpackPluginInstance } from "webpack";
1
+ import type { EntryProvider } from "../plugins/AbstractMultiPhaseLibraryAndEntryPlugin";
2
+ import { EntrypointFields, PlauditWordpressWebpackConfig, UnpackedBlockEntrypointInfo, VerifiedAdvancedOutputConfig } from "../shared";
3
+ import type { Compiler, Configuration, DynamicEntryPlugin, EntryObject, WebpackPluginInstance } from "webpack";
3
4
  import type WebpackRemoveEmptyScriptsPlugin from "webpack-remove-empty-scripts";
4
5
  export type VerifiedPlauditWordpressWebpackConfig = Required<Omit<PlauditWordpressWebpackConfig, 'variables' | 'src' | 'externals'>> & {
5
6
  variablesFilePath?: string;
@@ -18,5 +19,12 @@ export type CommonConfigProcessingResult = {
18
19
  };
19
20
  export declare function joinPossiblyAbsolutePaths(...paths: (string | undefined)[]): string;
20
21
  export declare function groupEntrypointsByAssetFile<T>(entrypoints: T[], entrypointNameExtractor: (t: T) => string): Map<string, T[]>;
21
- export declare function resolveEntryFromDirectory(commonConfig: CommonConfigProcessingResult, srcRoot: string, dest: VerifiedAdvancedOutputConfig): () => Promise<EntryObject>;
22
- export declare function commonMakeWebpackConfig(config: VerifiedPlauditWordpressWebpackConfig, commonConfig: CommonConfigProcessingResult, webpackConfig: Configuration, srcIsDirectory: boolean, dest: VerifiedAdvancedOutputConfig, src: string, srcRoot: string | string[], entry: () => Promise<EntryObject> | EntryObject, plugins: CommonPluginConfig['plugins']): Configuration;
22
+ export type BlockJsonExtensibleEntryObject = ExtensibleEntryObject<UnpackedBlockEntrypointInfo | string>;
23
+ export type EntryStaticNormalized = Awaited<ReturnType<ConstructorParameters<typeof DynamicEntryPlugin>[1]>>;
24
+ export type ExtensibleEntryObject<M> = {
25
+ [index: string]: Omit<EntryStaticNormalized[string], 'import'> & Required<NonNullable<Pick<EntryStaticNormalized[string], 'import'>>> & {
26
+ plauditMetadata: M;
27
+ };
28
+ };
29
+ export declare function resolveEntryFromDirectory(commonConfig: CommonConfigProcessingResult, srcRoot: string, dest: VerifiedAdvancedOutputConfig): EntryProvider<UnpackedBlockEntrypointInfo | string>;
30
+ export declare function commonMakeWebpackConfig(config: VerifiedPlauditWordpressWebpackConfig, commonConfig: CommonConfigProcessingResult, webpackConfig: Configuration, srcIsDirectory: boolean, dest: VerifiedAdvancedOutputConfig, src: string, srcRoot: string | string[], entry: (() => Promise<EntryObject> | EntryObject) | EntryObject, plugins: CommonPluginConfig['plugins']): Configuration;
@@ -33,37 +33,45 @@ function groupEntrypointsByAssetFile(entrypoints, entrypointNameExtractor) {
33
33
  }
34
34
  return seenPaths;
35
35
  }
36
- function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args = {}) {
37
- const { mapper = ep => ep, destDir } = args;
36
+ function mapToRealEntrypoints(entrypoint, dir, supportedExtensions, args) {
37
+ const { mapper = ep => ep, dest } = args;
38
38
  return (Array.isArray(entrypoint) ? entrypoint : [entrypoint])
39
39
  .map(ep => joinPossiblyAbsolutePaths(dir, mapper(ep)))
40
40
  .filter(ep => supportedExtensions(ep) && node_fs_1.default.statSync(ep, { throwIfNoEntry: false })?.isFile())
41
41
  .map(ep => {
42
42
  const parsedEntrypoint = node_path_1.default.parse(ep);
43
- return [joinPossiblyAbsolutePaths(destDir, node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name), { import: ep }];
43
+ const fakeEntrypointInfo = {
44
+ blockJsonOrigin: args.entrypointJsonOrigin,
45
+ entrypointField: shared_1.styleExtension.test(ep) ? 'style' : shared_1.scriptWithModuleExtension.test(ep) ? 'scriptModule' : 'script',
46
+ originalValue: ep,
47
+ entrypointName: parsedEntrypoint.name,
48
+ handle: (0, shared_1.convertUsageLocationsHandleToEmittableHandle)(dest.locations.handle, parsedEntrypoint.name)
49
+ };
50
+ return [joinPossiblyAbsolutePaths(dest.destination, node_path_1.default.basename(parsedEntrypoint.dir), parsedEntrypoint.name),
51
+ { import: [ep], plauditMetadata: fakeEntrypointInfo }];
44
52
  });
45
53
  }
46
54
  function parseEntrypointsJSON(dir, dest, supportedExtensions) {
47
- const entrypointsJSON = JSON.parse(node_fs_1.default.readFileSync(node_path_1.default.join(dir, 'entrypoints.json'), 'utf8'));
55
+ const entrypointJsonOrigin = node_path_1.default.join(dir, 'entrypoints.json');
56
+ const entrypointsJSON = JSON.parse(node_fs_1.default.readFileSync(entrypointJsonOrigin, 'utf8'));
48
57
  if (Array.isArray(entrypointsJSON)) {
49
- return mapToRealEntrypoints(entrypointsJSON, dir, supportedExtensions, { destDir: dest.destination });
58
+ return mapToRealEntrypoints(entrypointsJSON, dir, supportedExtensions, { dest, entrypointJsonOrigin });
50
59
  }
51
60
  else {
52
- return Object.entries(entrypointsJSON).map(([name, config]) => {
53
- if (typeof config === 'string') {
54
- return [name, joinPossiblyAbsolutePaths(dir, config)];
55
- }
56
- else if (Array.isArray(config)) {
57
- return [name, config.map(c => joinPossiblyAbsolutePaths(dir, c))];
61
+ return Object.entries(entrypointsJSON).flatMap(([name, config]) => {
62
+ if (Array.isArray(config)) {
63
+ return config.flatMap(c => mapToRealEntrypoints(c, dir, supportedExtensions, { dest, entrypointJsonOrigin }));
58
64
  }
59
65
  else {
66
+ return [[name, config]];
67
+ /* TODO: Fix compat with entrypoints.json in object mode
60
68
  if (typeof config.import === 'string') {
61
69
  config.import = joinPossiblyAbsolutePaths(dir, config.import);
62
- }
63
- else {
70
+ } else {
64
71
  config.import = config.import.map(c => joinPossiblyAbsolutePaths(dir, c));
65
72
  }
66
73
  return [name, config];
74
+ */
67
75
  }
68
76
  });
69
77
  }
@@ -158,8 +166,12 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
158
166
  .map(presentEntrypoint => {
159
167
  const overallSource = node_path_1.default.dirname(blockJsonOrigin);
160
168
  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))));
169
+ const handleSuffix = (0, shared_1.convertUsageLocationsHandleToEmittableHandle)(dest.locations.handle, overallSourceRelativeName);
161
170
  if (!entrypointNamesWithEffectiveDuplicates[presentEntrypoint.entrypointName]) {
162
- return { blockJsonOrigin, ...presentEntrypoint, handle: `${handlePrefix}/${overallSourceRelativeName}` };
171
+ return {
172
+ blockJsonOrigin, ...presentEntrypoint,
173
+ handle: `${handlePrefix}/${handleSuffix}`
174
+ };
163
175
  }
164
176
  const baseSuffix = `_${(0, shared_1.isStyleField)(presentEntrypoint.entrypointField) ? "style" : "script"}`;
165
177
  let count = 0, suffix = baseSuffix, deduplicatedEntrypointName;
@@ -174,7 +186,7 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
174
186
  ...presentEntrypoint,
175
187
  entrypointName: deduplicatedEntrypointName,
176
188
  extensionlessExpectedSrc: deduplicatedExtensionlessExpectedSrc,
177
- handle: `${handlePrefix}/${count ? overallSourceRelativeName + "_" + count : overallSourceRelativeName}`
189
+ handle: `${handlePrefix}/${count ? handleSuffix + "_" + count : handleSuffix}`
178
190
  };
179
191
  });
180
192
  rawEntrypoints.push(...resolvedBlockEntrypoints
@@ -182,22 +194,23 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
182
194
  return [
183
195
  resolvedBlockEntrypoint.entrypointName,
184
196
  {
185
- import: resolvedBlockEntrypoint.absoluteSrc,
186
- library: { name: (0, shared_1.packBlockEntrypointInfoForSmuggling)(resolvedBlockEntrypoint), type: `block-json-${dest.destination}` }
197
+ import: [resolvedBlockEntrypoint.absoluteSrc],
198
+ plauditMetadata: resolvedBlockEntrypoint
187
199
  }
188
200
  ];
189
201
  }));
190
- rawEntrypoints.push([blockJsonChunkName, { import: blockJsonOrigin, library: { name: "block-json-inclusion-assurance", type: `block-json-${dest.destination}` } }]);
202
+ rawEntrypoints.push([blockJsonChunkName, { import: [blockJsonOrigin], plauditMetadata: "block-json-inclusion-assurance" }]);
191
203
  wpmlFiles.push(node_path_1.default.join(dir, 'block.json'));
192
204
  }
193
205
  catch (e) {
194
206
  try {
195
- const packageJSON = JSON.parse(await promises_1.default.readFile(node_path_1.default.join(dir, 'package.json'), 'utf8'));
196
- if (packageJSON['main']) {
197
- rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['main'], dir, commonConfig.scriptExtension.test, { destDir: dest.destination }));
207
+ const packageJsonOrigin = node_path_1.default.join(dir, 'package.json');
208
+ const packageJson = JSON.parse(await promises_1.default.readFile(packageJsonOrigin, 'utf8'));
209
+ if (packageJson['main']) {
210
+ rawEntrypoints.push(...mapToRealEntrypoints(packageJson['main'], dir, commonConfig.scriptExtension.test, { dest, entrypointJsonOrigin: packageJsonOrigin }));
198
211
  }
199
- if (!processingModules && packageJSON['style']) {
200
- rawEntrypoints.push(...mapToRealEntrypoints(packageJSON['style'], dir, shared_1.styleExtension.test, { destDir: dest.destination }));
212
+ if (!processingModules && packageJson['style']) {
213
+ rawEntrypoints.push(...mapToRealEntrypoints(packageJson['style'], dir, shared_1.styleExtension.test, { dest, entrypointJsonOrigin: packageJsonOrigin }));
201
214
  }
202
215
  }
203
216
  catch (e) {
@@ -240,12 +253,12 @@ function resolveEntryFromDirectory(commonConfig, srcRoot, dest) {
240
253
  const wpmlEntrypointFiles = allEntrypoints.flatMap(e => e[1]);
241
254
  try {
242
255
  await promises_1.default.access(node_path_1.default.join(srcRoot, "wpml-config.xml"));
243
- currentEntry["wpml-config.xml"] = { import: [node_path_1.default.join(srcRoot, "wpml-config.xml"), ...wpmlEntrypointFiles], library: { type: `block-json-${dest.destination}` } };
256
+ currentEntry["wpml-config.xml"] = { import: [node_path_1.default.join(srcRoot, "wpml-config.xml"), ...wpmlEntrypointFiles], plauditMetadata: "wpml-config-xml" };
244
257
  }
245
258
  catch (e) {
246
259
  // If the wpml-config.xml file does not exist, just "import" the other files that will be used to build the emitted version
247
260
  if (wpmlEntrypointFiles.length) {
248
- currentEntry["wpml-config.xml"] = { import: wpmlEntrypointFiles, library: { type: `block-json-${dest.destination}` } };
261
+ currentEntry["wpml-config.xml"] = { import: wpmlEntrypointFiles, plauditMetadata: "wpml-config-xml" };
249
262
  }
250
263
  }
251
264
  }
@@ -374,7 +387,7 @@ function commonMakeWebpackConfig(config, commonConfig, webpackConfig, srcIsDirec
374
387
  delete require.cache[require.resolve(variablesFilePath)];
375
388
  updateCurrentVariables(require(variablesFilePath));
376
389
  }
377
- return entry();
390
+ return typeof entry === 'function' ? entry() : entry;
378
391
  },
379
392
  performance: {
380
393
  ...webpackConfig.performance,
@@ -18,6 +18,11 @@ export interface PotentiallyWriteableExpression extends EnclosableExpression {
18
18
  export declare function isEnclosableExpression(a: unknown): a is EnclosableExpression;
19
19
  export declare function isPotentiallyWriteableExpression(a: unknown): a is PotentiallyWriteableExpression;
20
20
  export declare abstract class AbstractEnclosableExpression extends Expr implements EnclosableExpression {
21
+ static readonly closers: Readonly<{
22
+ "(": ")";
23
+ "[": "]";
24
+ "{": "}";
25
+ }>;
21
26
  abstract toEnclosedForm(): string;
22
27
  not(): Not;
23
28
  }
@@ -31,9 +36,10 @@ export declare class Literal extends Expr {
31
36
  readonly expression: string;
32
37
  constructor(expression: string);
33
38
  toString(): string;
34
- static make(expression: string, enclosed: true): EnclosedLiteral;
35
- static make(expression: string, enclosureOpen: string, encloserClose: string): EnclosableLiteral;
36
- static make(expression: string, enclosed?: false | undefined): Literal;
39
+ static of(expression: string | PHPWriter, enclosed: true): EnclosedLiteral;
40
+ static of(expression: string | PHPWriter, enclosureOpen: keyof typeof AbstractEnclosableExpression.closers, encloserClose?: string): EnclosableLiteral;
41
+ static of(expression: string | PHPWriter, enclosureOpen: string, encloserClose: string): EnclosableLiteral;
42
+ static of(expression: string | PHPWriter, enclosed?: false | undefined): Literal;
37
43
  static name(expression: string): EnclosedLiteral;
38
44
  }
39
45
  export declare class EnclosedLiteral extends Literal implements EnclosableExpression {
@@ -97,6 +103,19 @@ export declare class Call extends EnclosedExpression implements PotentiallyWrite
97
103
  constructor(callee: string | EnclosableExpression, args: readonly unknown[]);
98
104
  toString(): string;
99
105
  }
106
+ export declare class Parameter extends Expr {
107
+ readonly value: unknown;
108
+ readonly name?: string | undefined;
109
+ constructor(value: unknown, name?: string | undefined);
110
+ toString(): string;
111
+ }
112
+ export declare class FirstClassCallable extends ParenthesesEnclosableExpression {
113
+ readonly name: EnclosableExpression;
114
+ constructor(name: EnclosableExpression);
115
+ static from(literal: string): FirstClassCallable;
116
+ toString(): string;
117
+ }
118
+ export declare const validPHPLabel: RegExp;
100
119
  type Assignable = EnclosedExpression & PotentiallyWriteableExpression;
101
120
  export declare class Assignment extends ParenthesesEnclosableExpression {
102
121
  readonly value: unknown;
@@ -140,7 +159,18 @@ export declare class PHPWriter {
140
159
  indent(): this;
141
160
  outdent(): this;
142
161
  setIndentation(level: number): this;
162
+ /**
163
+ * @param lines These are treated as literal *regardless of their types*
164
+ */
143
165
  append(...lines: (string | Expr)[]): this;
166
+ /**
167
+ * @param expr This is treated as literal *regardless of its type*
168
+ * @param opts flags to add additional markup around the expression
169
+ */
170
+ appendExpr(expr: string | Expr, opts?: {
171
+ chain?: boolean;
172
+ return?: boolean;
173
+ }): this;
144
174
  assign(assignee: ConstructorParameters<typeof Assignment>[0] | string, expression: unknown, opts?: {
145
175
  chain?: boolean;
146
176
  return?: boolean;
@@ -151,6 +181,11 @@ export declare class PHPWriter {
151
181
  withTest?: boolean | 'chainable';
152
182
  }): this;
153
183
  linebreak(): this;
184
+ /**
185
+ * @param func This is treated as literal *regardless of its type*
186
+ * @param args
187
+ * @param opts
188
+ */
154
189
  call(func: string | EnclosableExpression, args: unknown[], opts?: {
155
190
  chain?: boolean;
156
191
  assignTo?: ConstructorParameters<typeof Assignment>[0];
@@ -195,11 +230,5 @@ export declare class PHPWriter {
195
230
  includeNamespaceAndUse?: boolean;
196
231
  }): string;
197
232
  emitAsset(compilation: Compilation, file: string, assetInfo?: AssetInfo): void;
198
- /**
199
- * @param expr Unlike most other methods on this class, this is treated as literal *regardless of the argument's type*
200
- * @param opts
201
- * @private
202
- */
203
- private appendWithPossibleReturnAndChain;
204
233
  }
205
234
  export {};
@@ -3,7 +3,7 @@ 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.PHPWriter = exports.Constants = exports.Assignment = exports.Call = exports.ObjectAccess = exports.ArrayAccess = exports.Access = exports.Not = exports.Op = exports.Var = exports.EnclosableLiteral = exports.EnclosedLiteral = exports.Literal = exports.EnclosedExpression = exports.ParenthesesEnclosableExpression = exports.AbstractEnclosableExpression = exports.Expr = void 0;
6
+ exports.PHPWriter = exports.Constants = exports.Assignment = exports.validPHPLabel = exports.FirstClassCallable = exports.Parameter = exports.Call = exports.ObjectAccess = exports.ArrayAccess = exports.Access = exports.Not = exports.Op = exports.Var = exports.EnclosableLiteral = exports.EnclosedLiteral = exports.Literal = exports.EnclosedExpression = exports.ParenthesesEnclosableExpression = exports.AbstractEnclosableExpression = exports.Expr = void 0;
7
7
  exports.isEnclosableExpression = isEnclosableExpression;
8
8
  exports.isPotentiallyWriteableExpression = isPotentiallyWriteableExpression;
9
9
  const json_to_php_but_with____injection_1 = __importDefault(require("./json-to-php-but-with-__-injection"));
@@ -30,6 +30,7 @@ function isPotentiallyWriteableExpression(a) {
30
30
  return isEnclosableExpression(a) && 'potentiallyWritable' in a && a.potentiallyWritable === true;
31
31
  }
32
32
  class AbstractEnclosableExpression extends Expr {
33
+ static closers = Object.freeze({ "(": ")", "[": "]", "{": "}" });
33
34
  not() {
34
35
  return new Not(this);
35
36
  }
@@ -56,9 +57,12 @@ class Literal extends Expr {
56
57
  toString() {
57
58
  return this.expression;
58
59
  }
59
- static make(expression, enclosed = false, enclosureClose) {
60
+ static of(expression, enclosed = false, enclosureClose) {
61
+ if (expression instanceof PHPWriter) {
62
+ expression = expression.toString({ includeOpenPHP: false, includeNamespaceAndUse: false }).trim();
63
+ }
60
64
  if (typeof enclosed === 'string') {
61
- return new EnclosableLiteral(expression, enclosed, enclosureClose ?? enclosed);
65
+ return new EnclosableLiteral(expression, enclosed, enclosureClose ?? AbstractEnclosableExpression.closers[enclosed] ?? enclosed);
62
66
  }
63
67
  if (enclosed) {
64
68
  return new EnclosedLiteral(expression);
@@ -198,6 +202,34 @@ class Call extends EnclosedExpression {
198
202
  }
199
203
  }
200
204
  exports.Call = Call;
205
+ class Parameter extends Expr {
206
+ value;
207
+ name;
208
+ constructor(value, name) {
209
+ super();
210
+ this.value = value;
211
+ this.name = name;
212
+ }
213
+ toString() {
214
+ return this.name ? `${this.name}: ${Expr.convertJsonToPHP(this.value)}` : Expr.convertJsonToPHP(this.value);
215
+ }
216
+ }
217
+ exports.Parameter = Parameter;
218
+ class FirstClassCallable extends ParenthesesEnclosableExpression {
219
+ name;
220
+ constructor(name) {
221
+ super();
222
+ this.name = name;
223
+ }
224
+ static from(literal) {
225
+ return new FirstClassCallable(Literal.name(literal));
226
+ }
227
+ toString() {
228
+ return this.name.toEnclosedForm() + "(...)";
229
+ }
230
+ }
231
+ exports.FirstClassCallable = FirstClassCallable;
232
+ exports.validPHPLabel = /^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$/; // This is from https://www.php.net/manual/en/functions.user-defined.php
201
233
  class Assignment extends ParenthesesEnclosableExpression {
202
234
  value;
203
235
  push;
@@ -265,12 +297,23 @@ class PHPWriter {
265
297
  this.indentation = "\t".repeat(level);
266
298
  return this;
267
299
  }
300
+ /**
301
+ * @param lines These are treated as literal *regardless of their types*
302
+ */
268
303
  append(...lines) {
269
304
  for (const line of lines) {
270
305
  this.buffer.push(`${this.indentation}${line}`);
271
306
  }
272
307
  return this;
273
308
  }
309
+ /**
310
+ * @param expr This is treated as literal *regardless of its type*
311
+ * @param opts flags to add additional markup around the expression
312
+ */
313
+ appendExpr(expr, opts = {}) {
314
+ const res = (opts.return ? "return " : "") + expr.toString();
315
+ return this.append(!opts.chain ? res + ';' : res);
316
+ }
274
317
  assign(assignee, expression, opts = {}) {
275
318
  if (typeof assignee === 'string') {
276
319
  assignee = new Var(assignee);
@@ -285,10 +328,10 @@ class PHPWriter {
285
328
  this.scopeStack[this.scopeStack.length - 1].push(assignee.name);
286
329
  }
287
330
  }
288
- return this.appendWithPossibleReturnAndChain(new Assignment(assignee, expression), opts);
331
+ return this.appendExpr(new Assignment(assignee, expression), opts);
289
332
  }
290
333
  return(expression) {
291
- return this.append(`return ${Expr.convertJsonToPHP(expression)};`);
334
+ return this.appendExpr(Expr.convertJsonToPHP(expression), { return: true });
292
335
  }
293
336
  static(variable, opts = {}) {
294
337
  if (typeof variable === 'string') {
@@ -309,12 +352,17 @@ class PHPWriter {
309
352
  this.buffer.push("");
310
353
  return this;
311
354
  }
355
+ /**
356
+ * @param func This is treated as literal *regardless of its type*
357
+ * @param args
358
+ * @param opts
359
+ */
312
360
  call(func, args, opts = {}) {
313
361
  const functionCall = new Call(typeof func === 'string' ? Literal.name(func) : func, args);
314
362
  if (opts.assignTo) {
315
363
  return this.assign(opts.assignTo, functionCall, opts);
316
364
  }
317
- return this.appendWithPossibleReturnAndChain(functionCall, opts);
365
+ return this.appendExpr(functionCall, opts);
318
366
  }
319
367
  action(name, contents, args = {}) {
320
368
  return this.actionOrFilter('action', name, contents, args);
@@ -325,7 +373,7 @@ class PHPWriter {
325
373
  actionOrFilter(type, name, contents, args) {
326
374
  const { priority = 10, functionArgParameters = [], useVars = [], accountForAlreadyDoing } = args;
327
375
  const functionWriter = this.createSubwriter();
328
- let declarationFunctionText;
376
+ let declarationFunction;
329
377
  if (accountForAlreadyDoing) {
330
378
  if (functionArgParameters.length > 0 && accountForAlreadyDoing === true) {
331
379
  console.trace(`The accountForAlreadyDoing flag must be set to a list of default parameters when applied to ${type}s that take arguments`);
@@ -333,35 +381,35 @@ class PHPWriter {
333
381
  this.openPHP().openScope();
334
382
  const functionName = functionWriter.function(true, functionArgParameters, contents, { useVars, scopeActionDescription: `closing the function call for the ${name} ${type}.`, assignToName: true });
335
383
  this.append(functionWriter.toString().trim());
336
- declarationFunctionText = functionName + "(...)";
384
+ declarationFunction = new FirstClassCallable(functionName);
337
385
  this.if(Expr.call(`doing_${type}`, [name]))
338
386
  .call(functionName, accountForAlreadyDoing === true ? [] : accountForAlreadyDoing);
339
387
  }
340
388
  else {
341
389
  functionWriter.function(false, functionArgParameters, contents, { useVars, scopeActionDescription: `closing the function call for the ${name} ${type}.` });
342
- declarationFunctionText = functionWriter.toString().trim();
390
+ declarationFunction = Literal.of(functionWriter);
343
391
  }
344
392
  // The trailing comma inside the first item is necessary
345
- const declarationComponents = [`${Expr.convertJsonToPHP(name)}`, declarationFunctionText];
393
+ const additionArgs = [name, declarationFunction];
346
394
  const accepted_args = Math.max(functionArgParameters.length, 1); // This avoids us unnecessarily setting the accepted_args value to 0 for actions
347
395
  if (priority !== 10) {
348
- declarationComponents.push(priority.toString());
396
+ additionArgs.push(priority);
349
397
  if (accepted_args !== 1) {
350
- declarationComponents.push(accepted_args.toString());
398
+ additionArgs.push(accepted_args);
351
399
  }
352
400
  }
353
401
  else if (accepted_args !== 1) {
354
- declarationComponents.push(`accepted_args: ${accepted_args}`);
402
+ additionArgs.push(new Parameter(accepted_args, "accepted_args"));
355
403
  }
356
- const line = `add_${type}(${declarationComponents.join(", ")});`;
404
+ const line = Expr.call(`add_${type}`, additionArgs);
357
405
  if (accountForAlreadyDoing) {
358
406
  return this
359
407
  .else()
360
- .append(line)
408
+ .appendExpr(line)
361
409
  .endIf()
362
410
  .closeScope();
363
411
  }
364
- return this.openPHP().append(line);
412
+ return this.openPHP().appendExpr(line);
365
413
  }
366
414
  if(condition) {
367
415
  return this.openPHP().append(`if (${condition}) {`).indent();
@@ -384,6 +432,11 @@ class PHPWriter {
384
432
  console.trace('Anonymous functions cannot be assigned to a name');
385
433
  }
386
434
  }
435
+ if (typeof name === 'string') {
436
+ if (!exports.validPHPLabel.test(name)) {
437
+ throw new Error(`'${name}' is not a valid function name. Please see https://www.php.net/manual/en/functions.user-defined.php for what constitutes one`);
438
+ }
439
+ }
387
440
  const returningString = name === true;
388
441
  if (name === true) {
389
442
  name = this.generateFunctionName(args.assignToName);
@@ -550,14 +603,5 @@ class PHPWriter {
550
603
  const contents = this.toString() + "\n";
551
604
  compilation[file in compilation.assets ? 'updateAsset' : 'emitAsset'](file, new webpack_1.sources.RawSource(contents), { size: Buffer.byteLength(contents), ...assetInfo });
552
605
  }
553
- /**
554
- * @param expr Unlike most other methods on this class, this is treated as literal *regardless of the argument's type*
555
- * @param opts
556
- * @private
557
- */
558
- appendWithPossibleReturnAndChain(expr, opts) {
559
- const res = (opts.return ? "return " : "") + expr.toString();
560
- return this.append(!opts.chain ? res + ';' : res);
561
- }
562
606
  }
563
607
  exports.PHPWriter = PHPWriter;