@wp-blocks/make-pot 1.6.4 → 1.6.6

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.
Files changed (55) hide show
  1. package/README.md +2 -2
  2. package/lib/assets/block-i18n.js +41 -1
  3. package/lib/assets/package-i18n.js +38 -1
  4. package/lib/assets/theme-i18n.js +110 -1
  5. package/lib/assets/wp-plugin-i18n.js +39 -1
  6. package/lib/assets/wp-theme-i18n.js +37 -1
  7. package/lib/cli/getArgs.js +156 -1
  8. package/lib/cli/getArgs.js.map +2 -2
  9. package/lib/cli/getJsonArgs.js +82 -1
  10. package/lib/cli/parseCli.js +179 -1
  11. package/lib/cli.js +43 -1
  12. package/lib/const.js +111 -1
  13. package/lib/const.js.map +1 -1
  14. package/lib/extractors/auditStrings.js +177 -6
  15. package/lib/extractors/auditStrings.js.map +2 -2
  16. package/lib/extractors/css.js +69 -1
  17. package/lib/extractors/headers.js +253 -15
  18. package/lib/extractors/headers.js.map +2 -2
  19. package/lib/extractors/json.js +70 -1
  20. package/lib/extractors/packageJson.js +55 -1
  21. package/lib/extractors/php.js +79 -2
  22. package/lib/extractors/php.js.map +2 -2
  23. package/lib/extractors/schema.js +217 -3
  24. package/lib/extractors/text.js +41 -1
  25. package/lib/fs/fs.js +114 -2
  26. package/lib/fs/glob.js +103 -1
  27. package/lib/fs/glob.js.map +2 -2
  28. package/lib/index.js +64 -1
  29. package/lib/jsonCommand.js +51 -1
  30. package/lib/makeJson.js +28 -1
  31. package/lib/makePot.js +27 -1
  32. package/lib/parser/exec.js +94 -3
  33. package/lib/parser/exec.js.map +2 -2
  34. package/lib/parser/makeJson.js +393 -1
  35. package/lib/parser/makePot.js +48 -1
  36. package/lib/parser/patterns.js +54 -1
  37. package/lib/parser/process.js +85 -1
  38. package/lib/parser/process.js.map +2 -2
  39. package/lib/parser/progress.js +57 -1
  40. package/lib/parser/progress.js.map +2 -2
  41. package/lib/parser/taskRunner.js +65 -2
  42. package/lib/parser/taskRunner.js.map +2 -2
  43. package/lib/parser/tree.js +228 -2
  44. package/lib/parser/tree.js.map +2 -2
  45. package/lib/potCommand.js +36 -1
  46. package/lib/potCommand.js.map +2 -2
  47. package/lib/types.js +17 -1
  48. package/lib/types.js.map +1 -1
  49. package/lib/utils/common.js +161 -8
  50. package/lib/utils/common.js.map +2 -2
  51. package/lib/utils/extractors.js +69 -1
  52. package/lib/utils/output.js +59 -1
  53. package/lib/utils/output.js.map +3 -3
  54. package/package.json +3 -3
  55. package/tests/parse-php.test.js +47 -0
@@ -1 +1,179 @@
1
- "use strict";var w=Object.create;var u=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var _=Object.getOwnPropertyNames;var J=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty;var j=(t,n)=>{for(var e in n)u(t,e,{get:n[e],enumerable:!0})},k=(t,n,e,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let s of _(n))!T.call(t,s)&&s!==e&&u(t,s,{get:()=>n[s],enumerable:!(o=S(n,s))||o.enumerable});return t};var d=(t,n,e)=>(e=t!=null?w(J(t)):{},k(n||!t||!t.__esModule?u(e,"default",{value:t,enumerable:!0}):e,t)),v=t=>k(u({},"__esModule",{value:!0}),t);var $={};j($,{parseCliArgs:()=>C,parseJsonArgs:()=>N});module.exports=v($);var a=d(require("node:fs")),i=d(require("node:path")),A=d(require("node:process")),b=require("../const.js"),D=require("../fs/fs"),p=require("../utils/common.js");function O(t="/",n="default"){const e=t;try{return(0,a.accessSync)(i.join(e,`${n}.php`),a.default.constants.R_OK),"plugin"}catch{console.log(`the current working directory ${e} does not contain a ${n}.php file`)}try{return(0,a.accessSync)(i.join(e,"style.css"),a.default.constants.R_OK),"theme"}catch{console.log(`the current working directory ${e} does not contain a style.css file`)}return"generic"}function C(t){const n=t._[0]?.toString(),e=t._[1]?.toString()||"languages",o=n??".",s=e.startsWith("/")?e.slice(1):e,r=A.cwd(),c=t.slug&&typeof t.slug=="string"?t.slug:i.basename(i.resolve(r,o)),m=i.relative(r,o),P=i.relative(r,s);if(!t?.domain)t.domain=O(i.resolve(m),c);else switch(t.domain){case"plugin":case"theme":case"block":case"theme-block":break;default:console.error(`Invalid domain: ${t.domain}. Valid domains are: plugin, theme, block, theme-block, generic`),t.domain="generic"}const l={};if(t.headers&&Array.isArray(t.headers)){for(const g of t.headers)if(typeof g=="string"){const[f,y]=g.split(":");f&&y&&(l[f.trim()]=y.trim())}}const h={slug:c,debug:!!t.debug,domain:t.domain,paths:{cwd:m,out:P},options:{ignoreDomain:!!t?.ignoreDomain,packageName:String(t.packageName),silent:t.silent===!0,json:!!t.json,location:!!t?.location,headers:l,theme:!!t?.theme,output:!!t?.output,fileComment:t.fileComment?String(t.fileComment):void 0,charset:(0,D.getEncodingCharset)(t?.charset),skip:{js:!!t.skipJs,php:!!t.skipPhp,blade:!!t.skipBlade,blockJson:!!t.skipBlockJson,themeJson:!!t.skipThemeJson,audit:!!t.skipAudit},translationDomains:t.translationDomains?Array.isArray(t.translationDomains)?t.translationDomains.map(String):[String(t.translationDomains)]:void 0},patterns:{mergePaths:(0,p.stringstring)(t.mergePaths),subtractPaths:(0,p.stringstring)(t.subtractPaths),subtractAndMerge:!!t.subtractAndMerge,include:(0,p.stringstring)(t.include),exclude:[...(0,p.stringstring)(t.exclude),...b.DEFAULT_EXCLUDED_PATH]}};return h.paths.root=t.root?String(t.root):void 0,h}function N(t){const n=t._[0]||"build",e=t._[1]||"languages",o=A.cwd(),s=i.basename(i.resolve(o));let r;if(t.scriptName){const c=t.scriptName.toString().split(",").map(m=>m.trim());c.length===1&&(r=c[0])}return{timeStart:Date.now(),slug:s,source:n,destination:e,scriptName:r,allowedFormats:t.allowedFormats,purge:!!t.purge,stripUnused:!!t.stripUnused,prettyPrint:!!t.prettyPrint,debug:!!t.debug,paths:{cwd:o,out:i.join(o,e)}}}0&&(module.exports={parseCliArgs,parseJsonArgs});
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var parseCli_exports = {};
30
+ __export(parseCli_exports, {
31
+ parseCliArgs: () => parseCliArgs,
32
+ parseJsonArgs: () => parseJsonArgs
33
+ });
34
+ module.exports = __toCommonJS(parseCli_exports);
35
+ var import_node_fs = __toESM(require("node:fs"));
36
+ var path = __toESM(require("node:path"));
37
+ var process = __toESM(require("node:process"));
38
+ var import_const = require("../const.js");
39
+ var import_fs = require("../fs/fs");
40
+ var import_common = require("../utils/common.js");
41
+ function isThemeOrPlugin(currentPath = "/", slug = "default") {
42
+ const currentWorkingDirectory = currentPath;
43
+ try {
44
+ (0, import_node_fs.accessSync)(
45
+ path.join(currentWorkingDirectory, `${slug}.php`),
46
+ import_node_fs.default.constants.R_OK
47
+ );
48
+ return "plugin";
49
+ } catch (_err) {
50
+ console.log(
51
+ `the current working directory ${currentWorkingDirectory} does not contain a ${slug}.php file`
52
+ );
53
+ }
54
+ try {
55
+ (0, import_node_fs.accessSync)(
56
+ path.join(currentWorkingDirectory, "style.css"),
57
+ import_node_fs.default.constants.R_OK
58
+ );
59
+ return "theme";
60
+ } catch (_err) {
61
+ console.log(
62
+ `the current working directory ${currentWorkingDirectory} does not contain a style.css file`
63
+ );
64
+ }
65
+ return "generic";
66
+ }
67
+ function parseCliArgs(args) {
68
+ const pos1 = args._[0]?.toString();
69
+ const pos2 = args._[1]?.toString() || "languages";
70
+ const inputPath = pos1 ?? ".";
71
+ const outputPath = pos2.startsWith("/") ? pos2.slice(1) : pos2;
72
+ const currentWorkingDirectory = process.cwd();
73
+ const slug = args.slug && typeof args.slug === "string" ? args.slug : path.basename(path.resolve(currentWorkingDirectory, inputPath));
74
+ const cwd = path.relative(currentWorkingDirectory, inputPath);
75
+ const out = path.relative(currentWorkingDirectory, outputPath);
76
+ if (!args?.domain) {
77
+ args.domain = isThemeOrPlugin(path.resolve(cwd), slug);
78
+ } else {
79
+ switch (args.domain) {
80
+ case "plugin":
81
+ case "theme":
82
+ case "block":
83
+ case "theme-block":
84
+ break;
85
+ default:
86
+ console.error(
87
+ `Invalid domain: ${args.domain}. Valid domains are: plugin, theme, block, theme-block, generic`
88
+ );
89
+ args.domain = "generic";
90
+ }
91
+ }
92
+ const headers = {};
93
+ if (args.headers && Array.isArray(args.headers)) {
94
+ for (const header of args.headers) {
95
+ if (typeof header === "string") {
96
+ const [key, value] = header.split(":");
97
+ if (key && value) {
98
+ headers[key.trim()] = value.trim();
99
+ }
100
+ }
101
+ }
102
+ }
103
+ const parsedArgs = {
104
+ slug,
105
+ debug: !!args.debug,
106
+ domain: args.domain,
107
+ paths: { cwd, out },
108
+ options: {
109
+ ignoreDomain: !!args?.ignoreDomain,
110
+ packageName: String(args.packageName),
111
+ silent: args.silent === true,
112
+ // default is false
113
+ json: !!args.json,
114
+ location: !!args?.location,
115
+ headers,
116
+ theme: !!args?.theme,
117
+ output: !!args?.output,
118
+ fileComment: args.fileComment ? String(args.fileComment) : void 0,
119
+ charset: (0, import_fs.getEncodingCharset)(args?.charset),
120
+ skip: {
121
+ js: !!args.skipJs,
122
+ php: !!args.skipPhp,
123
+ blade: !!args.skipBlade,
124
+ blockJson: !!args.skipBlockJson,
125
+ themeJson: !!args.skipThemeJson,
126
+ audit: !!args.skipAudit
127
+ },
128
+ translationDomains: args.translationDomains ? Array.isArray(args.translationDomains) ? args.translationDomains.map(String) : [String(args.translationDomains)] : void 0
129
+ },
130
+ // Patterns
131
+ patterns: {
132
+ mergePaths: (0, import_common.stringstring)(args.mergePaths),
133
+ subtractPaths: (0, import_common.stringstring)(args.subtractPaths),
134
+ subtractAndMerge: !!args.subtractAndMerge,
135
+ include: (0, import_common.stringstring)(args.include),
136
+ exclude: [
137
+ ...(0, import_common.stringstring)(args.exclude),
138
+ ...import_const.DEFAULT_EXCLUDED_PATH
139
+ ]
140
+ }
141
+ };
142
+ parsedArgs.paths.root = args.root ? String(args.root) : void 0;
143
+ return parsedArgs;
144
+ }
145
+ function parseJsonArgs(args) {
146
+ const inputPath = args._[0] || "build";
147
+ const outputPath = args._[1] || "languages";
148
+ const currentWorkingDirectory = process.cwd();
149
+ const slug = path.basename(path.resolve(currentWorkingDirectory));
150
+ let scriptName;
151
+ if (args.scriptName) {
152
+ const scripts = args.scriptName.toString().split(",").map((s) => s.trim());
153
+ if (scripts.length === 1) {
154
+ scriptName = scripts[0];
155
+ }
156
+ }
157
+ return {
158
+ timeStart: Date.now(),
159
+ slug,
160
+ source: inputPath,
161
+ destination: outputPath,
162
+ scriptName,
163
+ allowedFormats: args.allowedFormats,
164
+ purge: !!args.purge,
165
+ stripUnused: !!args.stripUnused,
166
+ prettyPrint: !!args.prettyPrint,
167
+ debug: !!args.debug,
168
+ paths: {
169
+ cwd: currentWorkingDirectory,
170
+ out: path.join(currentWorkingDirectory, outputPath)
171
+ }
172
+ };
173
+ }
174
+ // Annotate the CommonJS export names for ESM import in node:
175
+ 0 && (module.exports = {
176
+ parseCliArgs,
177
+ parseJsonArgs
178
+ });
179
+ //# sourceMappingURL=parseCli.js.map
package/lib/cli.js CHANGED
@@ -1,2 +1,44 @@
1
1
  #!/usr/bin/env node
2
- "use strict";var d=Object.create;var n=Object.defineProperty;var l=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var y=Object.getPrototypeOf,J=Object.prototype.hasOwnProperty;var b=(o,r,s,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let e of A(r))!J.call(o,e)&&e!==s&&n(o,e,{get:()=>r[e],enumerable:!(a=l(r,e))||a.enumerable});return o};var m=(o,r,s)=>(s=o!=null?d(y(o)):{},b(r||!o||!o.__esModule?n(s,"default",{value:o,enumerable:!0}):s,o));var t=m(require("node:process")),c=m(require("yargs")),i=require("yargs/helpers"),p=require("./cli/getArgs.js"),f=require("./cli/getJsonArgs.js"),g=m(require("./jsonCommand.js")),k=m(require("./potCommand.js"));const j=c.default((0,i.hideBin)(t.default.argv)).options({makejson:{describe:"Make JSON file",type:"boolean",default:!1}}).parseSync();j.makejson?(0,g.default)((0,f.getJsonArgs)()):(0,k.default)((0,p.getArgs)());
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+ var import_node_process = __toESM(require("node:process"));
26
+ var yargs = __toESM(require("yargs"));
27
+ var import_helpers = require("yargs/helpers");
28
+ var import_getArgs = require("./cli/getArgs.js");
29
+ var import_getJsonArgs = require("./cli/getJsonArgs.js");
30
+ var import_jsonCommand = __toESM(require("./jsonCommand.js"));
31
+ var import_potCommand = __toESM(require("./potCommand.js"));
32
+ const r = yargs.default((0, import_helpers.hideBin)(import_node_process.default.argv)).options({
33
+ makejson: {
34
+ describe: "Make JSON file",
35
+ type: "boolean",
36
+ default: false
37
+ }
38
+ }).parseSync();
39
+ if (!r.makejson) {
40
+ (0, import_potCommand.default)((0, import_getArgs.getArgs)());
41
+ } else {
42
+ (0, import_jsonCommand.default)((0, import_getJsonArgs.getJsonArgs)());
43
+ }
44
+ //# sourceMappingURL=cli.js.map
package/lib/const.js CHANGED
@@ -1 +1,111 @@
1
- "use strict";var r=Object.create;var _=Object.defineProperty;var c=Object.getOwnPropertyDescriptor;var p=Object.getOwnPropertyNames;var l=Object.getPrototypeOf,u=Object.prototype.hasOwnProperty;var f=(t,e)=>{for(var m in e)_(t,m,{get:e[m],enumerable:!0})},n=(t,e,m,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of p(e))!u.call(t,s)&&s!==m&&_(t,s,{get:()=>e[s],enumerable:!(i=c(e,s))||i.enumerable});return t};var o=(t,e,m)=>(m=t!=null?r(l(t)):{},n(e||!t||!t.__esModule?_(m,"default",{value:t,enumerable:!0}):m,t)),h=t=>n(_({},"__esModule",{value:!0}),t);var T={};f(T,{DEFAULT_EXCLUDED_PATH:()=>F,IsoCodeRegex:()=>H,allowedFormats:()=>D,allowedFunctions:()=>E,defaultLocale:()=>A,fileRegex:()=>k,i18nFunctions:()=>L,modulePath:()=>P,pkgJsonHeaders:()=>j,pluginHeaders:()=>b,themeHeaders:()=>w});module.exports=h(T);var d=o(require("node:path")),x=o(require("./assets/package-i18n.js")),a=o(require("./assets/wp-plugin-i18n.js")),g=o(require("./assets/wp-theme-i18n.js"));const j=x.default,b=a.default,w=g.default,F=[".git","node_modules","vendor","build","dist","uploads","Gruntfile.js","webpack.config.js","**/*.min.js","tsconfig.js","**.test.**","tests"],H=/-([a-z]{2}_[A-Z]{2})\.po$/,k=/#:\s*(.*?)(?::\d+)?$/,A="en_US",D=["php","js","jsx","ts","tsx","mjs","cjs"],E=new Set(["__","_x","_n","_nx"]),L={__:["msgid","text_domain"],esc_attr__:["msgid","text_domain"],esc_html__:["msgid","text_domain"],esc_xml__:["msgid","text_domain"],_e:["msgid","text_domain"],esc_attr_e:["msgid","text_domain"],esc_html_e:["msgid","text_domain"],esc_xml_e:["msgid","text_domain"],_x:["msgid","msgctxt","text_domain"],_ex:["msgid","msgctxt","text_domain"],esc_attr_x:["msgid","msgctxt","text_domain"],esc_html_x:["msgid","msgctxt","text_domain"],esc_xml_x:["msgid","msgctxt","text_domain"],_n:["msgid","msgid_plural","number","text_domain"],_nx:["msgid","msgid_plural","number","msgctxt","text_domain"],_n_noop:["msgid","msgid_plural","text_domain"],_nx_noop:["msgid","msgid_plural","msgctxt","text_domain"],_:["msgid","text_domain"],_c:["msgid","text_domain"],_nc:["msgid","msgid_plural","number","text_domain"],__ngettext:["msgid","msgid_plural","number","text_domain"],__ngettext_noop:["msgid","msgid_plural","text_domain"]},P=d.default.resolve(__dirname,"..");0&&(module.exports={DEFAULT_EXCLUDED_PATH,IsoCodeRegex,allowedFormats,allowedFunctions,defaultLocale,fileRegex,i18nFunctions,modulePath,pkgJsonHeaders,pluginHeaders,themeHeaders});
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var const_exports = {};
30
+ __export(const_exports, {
31
+ DEFAULT_EXCLUDED_PATH: () => DEFAULT_EXCLUDED_PATH,
32
+ IsoCodeRegex: () => IsoCodeRegex,
33
+ allowedFormats: () => allowedFormats,
34
+ allowedFunctions: () => allowedFunctions,
35
+ defaultLocale: () => defaultLocale,
36
+ fileRegex: () => fileRegex,
37
+ i18nFunctions: () => i18nFunctions,
38
+ modulePath: () => modulePath,
39
+ pkgJsonHeaders: () => pkgJsonHeaders,
40
+ pluginHeaders: () => pluginHeaders,
41
+ themeHeaders: () => themeHeaders
42
+ });
43
+ module.exports = __toCommonJS(const_exports);
44
+ var import_node_path = __toESM(require("node:path"));
45
+ var import_package_i18n = __toESM(require("./assets/package-i18n.js"));
46
+ var import_wp_plugin_i18n = __toESM(require("./assets/wp-plugin-i18n.js"));
47
+ var import_wp_theme_i18n = __toESM(require("./assets/wp-theme-i18n.js"));
48
+ const pkgJsonHeaders = import_package_i18n.default;
49
+ const pluginHeaders = import_wp_plugin_i18n.default;
50
+ const themeHeaders = import_wp_theme_i18n.default;
51
+ const DEFAULT_EXCLUDED_PATH = [
52
+ ".git",
53
+ "node_modules",
54
+ "vendor",
55
+ "build",
56
+ "dist",
57
+ "uploads",
58
+ "Gruntfile.js",
59
+ "webpack.config.js",
60
+ "**/*.min.js",
61
+ "tsconfig.js",
62
+ "**/*.test.*",
63
+ "tests"
64
+ ];
65
+ const IsoCodeRegex = /-([a-z]{2}_[A-Z]{2})\.po$/;
66
+ const fileRegex = /#:\s*(.*?)(?::\d+)?$/;
67
+ const defaultLocale = "en_US";
68
+ const allowedFormats = ["php", "js", "jsx", "ts", "tsx", "mjs", "cjs"];
69
+ const allowedFunctions = /* @__PURE__ */ new Set(["__", "_x", "_n", "_nx"]);
70
+ const i18nFunctions = {
71
+ __: ["msgid", "text_domain"],
72
+ esc_attr__: ["msgid", "text_domain"],
73
+ esc_html__: ["msgid", "text_domain"],
74
+ esc_xml__: ["msgid", "text_domain"],
75
+ _e: ["msgid", "text_domain"],
76
+ esc_attr_e: ["msgid", "text_domain"],
77
+ esc_html_e: ["msgid", "text_domain"],
78
+ esc_xml_e: ["msgid", "text_domain"],
79
+ _x: ["msgid", "msgctxt", "text_domain"],
80
+ _ex: ["msgid", "msgctxt", "text_domain"],
81
+ esc_attr_x: ["msgid", "msgctxt", "text_domain"],
82
+ esc_html_x: ["msgid", "msgctxt", "text_domain"],
83
+ esc_xml_x: ["msgid", "msgctxt", "text_domain"],
84
+ _n: ["msgid", "msgid_plural", "number", "text_domain"],
85
+ _nx: ["msgid", "msgid_plural", "number", "msgctxt", "text_domain"],
86
+ _n_noop: ["msgid", "msgid_plural", "text_domain"],
87
+ _nx_noop: ["msgid", "msgid_plural", "msgctxt", "text_domain"],
88
+ // Compat.
89
+ _: ["msgid", "text_domain"],
90
+ // Deprecated.
91
+ _c: ["msgid", "text_domain"],
92
+ _nc: ["msgid", "msgid_plural", "number", "text_domain"],
93
+ __ngettext: ["msgid", "msgid_plural", "number", "text_domain"],
94
+ __ngettext_noop: ["msgid", "msgid_plural", "text_domain"]
95
+ };
96
+ const modulePath = import_node_path.default.resolve(__dirname, "..");
97
+ // Annotate the CommonJS export names for ESM import in node:
98
+ 0 && (module.exports = {
99
+ DEFAULT_EXCLUDED_PATH,
100
+ IsoCodeRegex,
101
+ allowedFormats,
102
+ allowedFunctions,
103
+ defaultLocale,
104
+ fileRegex,
105
+ i18nFunctions,
106
+ modulePath,
107
+ pkgJsonHeaders,
108
+ pluginHeaders,
109
+ themeHeaders
110
+ });
111
+ //# sourceMappingURL=const.js.map
package/lib/const.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/const.ts"],
4
- "sourcesContent": ["import path from \"node:path\";\nimport packagei18n from \"./assets/package-i18n.js\";\nimport wpPlugini18n from \"./assets/wp-plugin-i18n.js\";\nimport wpThemei18n from \"./assets/wp-theme-i18n.js\";\n\n/**\n * Theme Json metadata headers\n *\n */\nexport const pkgJsonHeaders = packagei18n;\n/**\n * The Plugin metadata headers\n * @link https://codex.wordpress.org/File_Header\n */\nexport const pluginHeaders = wpPlugini18n;\n/**\n * The Theme metadata headers\n * @link https://developer.wordpress.org/plugins/plugin-basics/header-requirements/\n */\nexport const themeHeaders = wpThemei18n;\n\n/**\n * The default list of paths to exclude from the pot file.\n * @link https://www.npmjs.com/package/glob#glob-primer\n */\nexport const DEFAULT_EXCLUDED_PATH = [\n\t\".git\",\n\t\"node_modules\",\n\t\"vendor\",\n\t\"build\",\n\t\"dist\",\n\t\"uploads\",\n\t\"Gruntfile.js\",\n\t\"webpack.config.js\",\n\t\"**/*.min.js\",\n\t\"tsconfig.js\",\n\t\"**.test.**\",\n\t\"tests\",\n];\n\n/**\n * The regex used to find the locale in the source code\n */\nexport const IsoCodeRegex = /-([a-z]{2}_[A-Z]{2})\\.po$/;\n\n/**\n * The regex used to find the filename in the source code\n */\nexport const fileRegex = /#:\\s*(.*?)(?::\\d+)?$/;\n\nexport const defaultLocale = \"en_US\";\n\n/**\n * The files that are allowed to be parsed using tree sitter\n *\n * Json and text files are parsed in a different way\n */\nexport const allowedFormats = [\"php\", \"js\", \"jsx\", \"ts\", \"tsx\", \"mjs\", \"cjs\"];\n\n/**\n * The functions that are allowed to be \"converted\" using babel during the make-json process\n */\nexport const allowedFunctions = new Set([\"__\", \"_x\", \"_n\", \"_nx\"]);\n\n/**\n * The default functions to use for i18n.\n */\nexport const i18nFunctions = {\n\t__: [\"msgid\", \"text_domain\"],\n\tesc_attr__: [\"msgid\", \"text_domain\"],\n\tesc_html__: [\"msgid\", \"text_domain\"],\n\tesc_xml__: [\"msgid\", \"text_domain\"],\n\t_e: [\"msgid\", \"text_domain\"],\n\tesc_attr_e: [\"msgid\", \"text_domain\"],\n\tesc_html_e: [\"msgid\", \"text_domain\"],\n\tesc_xml_e: [\"msgid\", \"text_domain\"],\n\t_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\t_ex: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\tesc_attr_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\tesc_html_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\tesc_xml_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\t_n: [\"msgid\", \"msgid_plural\", \"number\", \"text_domain\"],\n\t_nx: [\"msgid\", \"msgid_plural\", \"number\", \"msgctxt\", \"text_domain\"],\n\t_n_noop: [\"msgid\", \"msgid_plural\", \"text_domain\"],\n\t_nx_noop: [\"msgid\", \"msgid_plural\", \"msgctxt\", \"text_domain\"],\n\n\t// Compat.\n\t_: [\"msgid\", \"text_domain\"],\n\n\t// Deprecated.\n\t_c: [\"msgid\", \"text_domain\"],\n\t_nc: [\"msgid\", \"msgid_plural\", \"number\", \"text_domain\"],\n\t__ngettext: [\"msgid\", \"msgid_plural\", \"number\", \"text_domain\"],\n\t__ngettext_noop: [\"msgid\", \"msgid_plural\", \"text_domain\"],\n};\n\n/**\n * @var modulePath The path to the module folder containing this file\n */\nexport const modulePath = path.resolve(__dirname, \"..\");\n"],
4
+ "sourcesContent": ["import path from \"node:path\";\nimport packagei18n from \"./assets/package-i18n.js\";\nimport wpPlugini18n from \"./assets/wp-plugin-i18n.js\";\nimport wpThemei18n from \"./assets/wp-theme-i18n.js\";\n\n/**\n * Theme Json metadata headers\n *\n */\nexport const pkgJsonHeaders = packagei18n;\n/**\n * The Plugin metadata headers\n * @link https://codex.wordpress.org/File_Header\n */\nexport const pluginHeaders = wpPlugini18n;\n/**\n * The Theme metadata headers\n * @link https://developer.wordpress.org/plugins/plugin-basics/header-requirements/\n */\nexport const themeHeaders = wpThemei18n;\n\n/**\n * The default list of paths to exclude from the pot file.\n * @link https://www.npmjs.com/package/glob#glob-primer\n */\nexport const DEFAULT_EXCLUDED_PATH = [\n\t\".git\",\n\t\"node_modules\",\n\t\"vendor\",\n\t\"build\",\n\t\"dist\",\n\t\"uploads\",\n\t\"Gruntfile.js\",\n\t\"webpack.config.js\",\n\t\"**/*.min.js\",\n\t\"tsconfig.js\",\n\t\"**/*.test.*\",\n\t\"tests\",\n];\n\n/**\n * The regex used to find the locale in the source code\n */\nexport const IsoCodeRegex = /-([a-z]{2}_[A-Z]{2})\\.po$/;\n\n/**\n * The regex used to find the filename in the source code\n */\nexport const fileRegex = /#:\\s*(.*?)(?::\\d+)?$/;\n\nexport const defaultLocale = \"en_US\";\n\n/**\n * The files that are allowed to be parsed using tree sitter\n *\n * Json and text files are parsed in a different way\n */\nexport const allowedFormats = [\"php\", \"js\", \"jsx\", \"ts\", \"tsx\", \"mjs\", \"cjs\"];\n\n/**\n * The functions that are allowed to be \"converted\" using babel during the make-json process\n */\nexport const allowedFunctions = new Set([\"__\", \"_x\", \"_n\", \"_nx\"]);\n\n/**\n * The default functions to use for i18n.\n */\nexport const i18nFunctions = {\n\t__: [\"msgid\", \"text_domain\"],\n\tesc_attr__: [\"msgid\", \"text_domain\"],\n\tesc_html__: [\"msgid\", \"text_domain\"],\n\tesc_xml__: [\"msgid\", \"text_domain\"],\n\t_e: [\"msgid\", \"text_domain\"],\n\tesc_attr_e: [\"msgid\", \"text_domain\"],\n\tesc_html_e: [\"msgid\", \"text_domain\"],\n\tesc_xml_e: [\"msgid\", \"text_domain\"],\n\t_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\t_ex: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\tesc_attr_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\tesc_html_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\tesc_xml_x: [\"msgid\", \"msgctxt\", \"text_domain\"],\n\t_n: [\"msgid\", \"msgid_plural\", \"number\", \"text_domain\"],\n\t_nx: [\"msgid\", \"msgid_plural\", \"number\", \"msgctxt\", \"text_domain\"],\n\t_n_noop: [\"msgid\", \"msgid_plural\", \"text_domain\"],\n\t_nx_noop: [\"msgid\", \"msgid_plural\", \"msgctxt\", \"text_domain\"],\n\n\t// Compat.\n\t_: [\"msgid\", \"text_domain\"],\n\n\t// Deprecated.\n\t_c: [\"msgid\", \"text_domain\"],\n\t_nc: [\"msgid\", \"msgid_plural\", \"number\", \"text_domain\"],\n\t__ngettext: [\"msgid\", \"msgid_plural\", \"number\", \"text_domain\"],\n\t__ngettext_noop: [\"msgid\", \"msgid_plural\", \"text_domain\"],\n};\n\n/**\n * @var modulePath The path to the module folder containing this file\n */\nexport const modulePath = path.resolve(__dirname, \"..\");\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAiB;AACjB,0BAAwB;AACxB,4BAAyB;AACzB,2BAAwB;AAMjB,MAAM,iBAAiB,oBAAAA;AAKvB,MAAM,gBAAgB,sBAAAC;AAKtB,MAAM,eAAe,qBAAAC;AAMrB,MAAM,wBAAwB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAKO,MAAM,eAAe;AAKrB,MAAM,YAAY;AAElB,MAAM,gBAAgB;AAOtB,MAAM,iBAAiB,CAAC,OAAO,MAAM,OAAO,MAAM,OAAO,OAAO,KAAK;AAKrE,MAAM,mBAAmB,oBAAI,IAAI,CAAC,MAAM,MAAM,MAAM,KAAK,CAAC;AAK1D,MAAM,gBAAgB;AAAA,EAC5B,IAAI,CAAC,SAAS,aAAa;AAAA,EAC3B,YAAY,CAAC,SAAS,aAAa;AAAA,EACnC,YAAY,CAAC,SAAS,aAAa;AAAA,EACnC,WAAW,CAAC,SAAS,aAAa;AAAA,EAClC,IAAI,CAAC,SAAS,aAAa;AAAA,EAC3B,YAAY,CAAC,SAAS,aAAa;AAAA,EACnC,YAAY,CAAC,SAAS,aAAa;AAAA,EACnC,WAAW,CAAC,SAAS,aAAa;AAAA,EAClC,IAAI,CAAC,SAAS,WAAW,aAAa;AAAA,EACtC,KAAK,CAAC,SAAS,WAAW,aAAa;AAAA,EACvC,YAAY,CAAC,SAAS,WAAW,aAAa;AAAA,EAC9C,YAAY,CAAC,SAAS,WAAW,aAAa;AAAA,EAC9C,WAAW,CAAC,SAAS,WAAW,aAAa;AAAA,EAC7C,IAAI,CAAC,SAAS,gBAAgB,UAAU,aAAa;AAAA,EACrD,KAAK,CAAC,SAAS,gBAAgB,UAAU,WAAW,aAAa;AAAA,EACjE,SAAS,CAAC,SAAS,gBAAgB,aAAa;AAAA,EAChD,UAAU,CAAC,SAAS,gBAAgB,WAAW,aAAa;AAAA;AAAA,EAG5D,GAAG,CAAC,SAAS,aAAa;AAAA;AAAA,EAG1B,IAAI,CAAC,SAAS,aAAa;AAAA,EAC3B,KAAK,CAAC,SAAS,gBAAgB,UAAU,aAAa;AAAA,EACtD,YAAY,CAAC,SAAS,gBAAgB,UAAU,aAAa;AAAA,EAC7D,iBAAiB,CAAC,SAAS,gBAAgB,aAAa;AACzD;AAKO,MAAM,aAAa,iBAAAC,QAAK,QAAQ,WAAW,IAAI;",
6
6
  "names": ["packagei18n", "wpPlugini18n", "wpThemei18n", "path"]
7
7
  }
@@ -1,6 +1,177 @@
1
- "use strict";var p=Object.create;var c=Object.defineProperty;var f=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var E=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var _=(t,s)=>{for(var e in s)c(t,e,{get:s[e],enumerable:!0})},g=(t,s,e,o)=>{if(s&&typeof s=="object"||typeof s=="function")for(let r of R(s))!P.call(t,r)&&r!==e&&c(t,r,{get:()=>s[r],enumerable:!(o=f(s,r))||o.enumerable});return t};var S=(t,s,e)=>(e=t!=null?p(E(t)):{},g(s||!t||!t.__esModule?c(e,"default",{value:t,enumerable:!0}):e,t)),D=t=>g(c({},"__esModule",{value:!0}),t);var $={};_($,{audit:()=>T,default:()=>L});module.exports=D($);var u=require("node:fs"),d=S(require("node:path"));function T(t,s){const e=new m(t.domain);if(e.auditStrings(s.blocks),console.log(`
2
- Audit Complete!`),e.getResults().length===0){console.log("No issues found! \u{1F389}");try{(0,u.unlinkSync)(d.default.join(t.paths.cwd,"audit.log"))}catch{}}else{if(console.log(`Found ${e.getResults().length} issues!`),t.options?.silent!==!0){const o=e.getResults().join(`
3
- `);console.log(o)}(0,u.writeFileSync)(d.default.join(t.paths.cwd,"audit.log"),e.getResults().join(`
4
- `))}}class m{SPRINTF_PLACEHOLDER_REGEX=/%(?:\d+\$)?[+-]?(?:[ 0]|'.)?-?\d*(?:\.\d+)?[bcdeEfFgGhHosuxX]/g;UNORDERED_SPRINTF_PLACEHOLDER_REGEX=/%(?!(\d+)\$)[+-]?(?:[ 0]|'.)?-?\d*(?:\.\d+)?[bcdeEfFgGhHosuxX]/g;projectType;results=[];constructor(s){this.projectType=s}getFileHeaders(s){return{plugin:["Plugin Name:","Plugin URI:","Description:","Author:","Author URI:","Version:","Text Domain:","Domain Path:","Network:","Requires at least:","Requires PHP:"],theme:["Theme Name:","Theme URI:","Author:","Author URI:","Description:","Version:","License:","License URI:","Text Domain:","Domain Path:","Tags:","Requires at least:","Requires PHP:"]}[s]||[]}auditStrings(s){for(const e of s){const o=e.comments?.reference||[],r=o.length>0?`(${o[0]})`:"";if(!e.msgid)continue;if((!e.comments?.extracted||e.comments.extracted.length===0)&&(e.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX)||[]).length>=1){const n=`The string "${e.msgid}" contains placeholders but has no "translators:" comment to clarify their meaning. ${r}`;this.results.push(n)}if(e.comments?.extracted&&e.comments.extracted.length>0){let n=e.comments.extracted;n=n.filter(i=>{for(const h of this.getFileHeaders(this.projectType))if(i.startsWith(h))return!1;return!0});const a=[];n=n.filter(i=>a.includes(i)?!1:(a.push(i),!0));const l=n.length;if(l>1){const i=`The string "${e.msgid}" has ${l} different translator comments. ${r}
5
- ${n.join(`
6
- `)}`;this.results.push(i)}}if(e.msgid.trim().replace(/^(['"])(.*)\1$/s,"$2").replace(this.SPRINTF_PLACEHOLDER_REGEX,"")===""){const n=`Found string without translatable content. ${r}`;this.results.push(n)}if((e.msgid.match(this.UNORDERED_SPRINTF_PLACEHOLDER_REGEX)||[]).length>=2){const n=`Multiple placeholders should be ordered. ${r}`;this.results.push(n)}if(e.msgid_plural){const n=e.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX)||[],a=e.msgid_plural.match(this.SPRINTF_PLACEHOLDER_REGEX)||[];if(n.length<a.length){const l=`Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals ${r}`;this.results.push(l)}else{const l=[...n].sort(),i=[...a].sort();if(JSON.stringify(l)!==JSON.stringify(i)){const h=`Mismatched placeholders for singular and plural string. ${r}`;this.results.push(h)}}}}}getResults(){return this.results}}var L=m;0&&(module.exports={audit});
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var auditStrings_exports = {};
30
+ __export(auditStrings_exports, {
31
+ audit: () => audit,
32
+ default: () => auditStrings_default
33
+ });
34
+ module.exports = __toCommonJS(auditStrings_exports);
35
+ var import_node_fs = require("node:fs");
36
+ var import_node_path = __toESM(require("node:path"));
37
+ function audit(args, translationsUnion) {
38
+ const auditor = new StringAuditor(args.domain);
39
+ auditor.auditStrings(translationsUnion.blocks);
40
+ console.log("Audit Complete!");
41
+ if (auditor.getResults().length === 0) {
42
+ console.log("No issues found! \u{1F389}");
43
+ try {
44
+ (0, import_node_fs.unlinkSync)(import_node_path.default.join(args.paths.cwd, "audit.log"));
45
+ } catch (_error) {
46
+ }
47
+ } else {
48
+ console.log(`Found ${auditor.getResults().length} issues!`);
49
+ if (args.options?.silent !== true) {
50
+ const results = auditor.getResults().join("\n");
51
+ console.log(results);
52
+ }
53
+ (0, import_node_fs.writeFileSync)(import_node_path.default.join(args.paths.cwd, "audit.log"), auditor.getResults().join("\n"));
54
+ }
55
+ }
56
+ class StringAuditor {
57
+ SPRINTF_PLACEHOLDER_REGEX = /%(?:\d+\$)?[+-]?(?:[ 0]|'.)?-?\d*(?:\.\d+)?[bcdeEfFgGhHosuxX]/g;
58
+ UNORDERED_SPRINTF_PLACEHOLDER_REGEX = /%(?!(\d+)\$)[+-]?(?:[ 0]|'.)?-?\d*(?:\.\d+)?[bcdeEfFgGhHosuxX]/g;
59
+ projectType;
60
+ /**
61
+ * The results of the audit process
62
+ */
63
+ results = [];
64
+ constructor(projectType) {
65
+ this.projectType = projectType;
66
+ }
67
+ getFileHeaders(projectType) {
68
+ const headers = {
69
+ plugin: [
70
+ "Plugin Name:",
71
+ "Plugin URI:",
72
+ "Description:",
73
+ "Author:",
74
+ "Author URI:",
75
+ "Version:",
76
+ "Text Domain:",
77
+ "Domain Path:",
78
+ "Network:",
79
+ "Requires at least:",
80
+ "Requires PHP:"
81
+ ],
82
+ theme: [
83
+ "Theme Name:",
84
+ "Theme URI:",
85
+ "Author:",
86
+ "Author URI:",
87
+ "Description:",
88
+ "Version:",
89
+ "License:",
90
+ "License URI:",
91
+ "Text Domain:",
92
+ "Domain Path:",
93
+ "Tags:",
94
+ "Requires at least:",
95
+ "Requires PHP:"
96
+ ]
97
+ };
98
+ return headers[projectType] || [];
99
+ }
100
+ auditStrings(translations) {
101
+ for (const translation of translations) {
102
+ const references = translation.comments?.reference || [];
103
+ const location = references.length > 0 ? `(${references[0]})` : "";
104
+ if (!translation.msgid) {
105
+ continue;
106
+ }
107
+ if ((!translation.comments?.extracted || translation.comments.extracted.length === 0) && (translation.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX) || []).length >= 1) {
108
+ const message = `The string "${translation.msgid}" contains placeholders but has no "translators:" comment to clarify their meaning. ${location}`;
109
+ this.results.push(message);
110
+ }
111
+ if (translation.comments?.extracted && translation.comments.extracted.length > 0) {
112
+ let comments = translation.comments.extracted;
113
+ comments = comments.filter((comment) => {
114
+ for (const fileHeader of this.getFileHeaders(this.projectType)) {
115
+ if (comment.startsWith(fileHeader)) {
116
+ return false;
117
+ }
118
+ }
119
+ return true;
120
+ });
121
+ const uniqueComments = [];
122
+ comments = comments.filter((comment) => {
123
+ if (uniqueComments.includes(comment)) {
124
+ return false;
125
+ }
126
+ uniqueComments.push(comment);
127
+ return true;
128
+ });
129
+ const commentsCount = comments.length;
130
+ if (commentsCount > 1) {
131
+ const message = `The string "${translation.msgid}" has ${commentsCount} different translator comments. ${location}
132
+ ${comments.join("\n")}`;
133
+ this.results.push(message);
134
+ }
135
+ }
136
+ const nonPlaceholderContent = translation.msgid.trim().replace(/^(['"])(.*)\1$/s, "$2").replace(this.SPRINTF_PLACEHOLDER_REGEX, "");
137
+ if (nonPlaceholderContent === "") {
138
+ const message = `Found string without translatable content. ${location}`;
139
+ this.results.push(message);
140
+ }
141
+ const unorderedMatches = translation.msgid.match(this.UNORDERED_SPRINTF_PLACEHOLDER_REGEX) || [];
142
+ const unorderedMatchesCount = unorderedMatches.length;
143
+ if (unorderedMatchesCount >= 2) {
144
+ const message = `Multiple placeholders should be ordered. ${location}`;
145
+ this.results.push(message);
146
+ }
147
+ if (translation.msgid_plural) {
148
+ const singlePlaceholders = translation.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX) || [];
149
+ const pluralPlaceholders = translation.msgid_plural.match(this.SPRINTF_PLACEHOLDER_REGEX) || [];
150
+ if (singlePlaceholders.length < pluralPlaceholders.length) {
151
+ const message = `Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals ${location}`;
152
+ this.results.push(message);
153
+ } else {
154
+ const sortedSinglePlaceholders = [...singlePlaceholders].sort();
155
+ const sortedPluralPlaceholders = [...pluralPlaceholders].sort();
156
+ if (JSON.stringify(sortedSinglePlaceholders) !== JSON.stringify(sortedPluralPlaceholders)) {
157
+ const message = `Mismatched placeholders for singular and plural string. ${location}`;
158
+ this.results.push(message);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ /**
165
+ * Get the results of the audit process
166
+ * @returns An array of messages
167
+ */
168
+ getResults() {
169
+ return this.results;
170
+ }
171
+ }
172
+ var auditStrings_default = StringAuditor;
173
+ // Annotate the CommonJS export names for ESM import in node:
174
+ 0 && (module.exports = {
175
+ audit
176
+ });
177
+ //# sourceMappingURL=auditStrings.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/extractors/auditStrings.ts"],
4
- "sourcesContent": ["import { unlinkSync, writeFileSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { Block, SetOfBlocks } from \"gettext-merger\";\r\nimport type { Args } from \"../types.js\";\r\n\r\nexport function audit(args: Args, translationsUnion: SetOfBlocks) {\r\n\t/** Run the audit process */\r\n\tconst auditor = new StringAuditor(args.domain);\r\n\tauditor.auditStrings(translationsUnion.blocks);\r\n\r\n\t/** Get and print the results of the audit process */\r\n\tconsole.log(\"\\nAudit Complete!\");\r\n\tif (auditor.getResults().length === 0) {\r\n\t\tconsole.log(\"No issues found! \uD83C\uDF89\");\r\n\t\t// if there are no errors, we can remove the audit.log file\r\n\t\ttry {\r\n\t\t\tunlinkSync(path.join(args.paths.cwd, \"audit.log\"));\r\n\t\t} catch (_error) {\r\n\t\t\t//ignore\r\n\t\t}\r\n\t} else {\r\n\t\tconsole.log(`Found ${auditor.getResults().length} issues!`);\r\n\t\t// Print the results if not in silent mode\r\n\t\tif (args.options?.silent !== true) {\r\n\t\t\tconst results = auditor.getResults().join(\"\\n\");\r\n\t\t\tconsole.log(results);\r\n\t\t}\r\n\t\t/** Write the audit results to a file */\r\n\t\twriteFileSync(path.join(args.paths.cwd, \"audit.log\"), auditor.getResults().join(\"\\n\"));\r\n\t}\r\n}\r\n\r\n/**\r\n * Class to audit gettext strings\r\n *\r\n * Example usage:\r\n * const auditor = new StringAuditor('plugin');\r\n * auditor.auditStrings(translationBlocks);\r\n */\r\nclass StringAuditor {\r\n\tprivate readonly SPRINTF_PLACEHOLDER_REGEX =\r\n\t\t/%(?:\\d+\\$)?[+-]?(?:[ 0]|'.)?-?\\d*(?:\\.\\d+)?[bcdeEfFgGhHosuxX]/g;\r\n\tprivate readonly UNORDERED_SPRINTF_PLACEHOLDER_REGEX =\r\n\t\t/%(?!(\\d+)\\$)[+-]?(?:[ 0]|'.)?-?\\d*(?:\\.\\d+)?[bcdeEfFgGhHosuxX]/g;\r\n\tprivate projectType: string;\r\n\r\n\t/**\r\n\t * The results of the audit process\r\n\t */\r\n\tpublic results: string[] = [];\r\n\r\n\tconstructor(projectType: string) {\r\n\t\tthis.projectType = projectType;\r\n\t}\r\n\r\n\tprivate getFileHeaders(projectType: string): string[] {\r\n\t\t// Implement based on your requirements\r\n\t\t// This would be the equivalent of the PHP get_file_headers method\r\n\t\tconst headers: Record<string, string[]> = {\r\n\t\t\tplugin: [\r\n\t\t\t\t\"Plugin Name:\",\r\n\t\t\t\t\"Plugin URI:\",\r\n\t\t\t\t\"Description:\",\r\n\t\t\t\t\"Author:\",\r\n\t\t\t\t\"Author URI:\",\r\n\t\t\t\t\"Version:\",\r\n\t\t\t\t\"Text Domain:\",\r\n\t\t\t\t\"Domain Path:\",\r\n\t\t\t\t\"Network:\",\r\n\t\t\t\t\"Requires at least:\",\r\n\t\t\t\t\"Requires PHP:\",\r\n\t\t\t],\r\n\t\t\ttheme: [\r\n\t\t\t\t\"Theme Name:\",\r\n\t\t\t\t\"Theme URI:\",\r\n\t\t\t\t\"Author:\",\r\n\t\t\t\t\"Author URI:\",\r\n\t\t\t\t\"Description:\",\r\n\t\t\t\t\"Version:\",\r\n\t\t\t\t\"License:\",\r\n\t\t\t\t\"License URI:\",\r\n\t\t\t\t\"Text Domain:\",\r\n\t\t\t\t\"Domain Path:\",\r\n\t\t\t\t\"Tags:\",\r\n\t\t\t\t\"Requires at least:\",\r\n\t\t\t\t\"Requires PHP:\",\r\n\t\t\t],\r\n\t\t};\r\n\r\n\t\treturn headers[projectType] || [];\r\n\t}\r\n\r\n\tauditStrings(translations: Block[]): void {\r\n\t\tfor (const translation of translations) {\r\n\t\t\tconst references = translation.comments?.reference || [];\r\n\r\n\t\t\t// File headers don't have any file references\r\n\t\t\tconst location = references.length > 0 ? `(${references[0]})` : \"\";\r\n\r\n\t\t\t// Check 0: Flag strings without msgid is the header so it's not a translation and should be ignored\r\n\t\t\tif (!translation.msgid) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// Check 1: Flag strings with placeholders that should have translator comments\r\n\t\t\tif (\r\n\t\t\t\t(!translation.comments?.extracted ||\r\n\t\t\t\t\ttranslation.comments.extracted.length === 0) &&\r\n\t\t\t\t(translation.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX) || [])\r\n\t\t\t\t\t.length >= 1\r\n\t\t\t) {\r\n\t\t\t\tconst message = `The string \"${translation.msgid}\" contains placeholders but has no \"translators:\" comment to clarify their meaning. ${location}`;\r\n\t\t\t\tthis.results.push(message);\r\n\t\t\t}\r\n\r\n\t\t\t// Check 2: Flag strings with different translator comments\r\n\t\t\tif (\r\n\t\t\t\ttranslation.comments?.extracted &&\r\n\t\t\t\ttranslation.comments.extracted.length > 0\r\n\t\t\t) {\r\n\t\t\t\tlet comments = translation.comments.extracted;\r\n\r\n\t\t\t\t// Remove plugin header information from comments\r\n\t\t\t\tcomments = comments.filter((comment) => {\r\n\t\t\t\t\tfor (const fileHeader of this.getFileHeaders(this.projectType)) {\r\n\t\t\t\t\t\tif (comment.startsWith(fileHeader)) {\r\n\t\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tconst uniqueComments: string[] = [];\r\n\r\n\t\t\t\t// Remove duplicate comments\r\n\t\t\t\tcomments = comments.filter((comment) => {\r\n\t\t\t\t\tif (uniqueComments.includes(comment)) {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tuniqueComments.push(comment);\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tconst commentsCount = comments.length;\r\n\r\n\t\t\t\tif (commentsCount > 1) {\r\n\t\t\t\t\tconst message = `The string \"${translation.msgid}\" has ${commentsCount} different translator comments. ${location}\\n${comments.join(\"\\n\")}`;\r\n\t\t\t\t\tthis.results.push(message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Extract non-placeholder content from the string\r\n\t\t\tconst nonPlaceholderContent = translation.msgid\r\n\t\t\t\t.trim()\r\n\t\t\t\t.replace(/^(['\"])(.*)\\1$/s, \"$2\")\r\n\t\t\t\t.replace(this.SPRINTF_PLACEHOLDER_REGEX, \"\");\r\n\r\n\t\t\t// Check 3: Flag empty strings without any translatable content\r\n\t\t\tif (nonPlaceholderContent === \"\") {\r\n\t\t\t\tconst message = `Found string without translatable content. ${location}`;\r\n\t\t\t\tthis.results.push(message);\r\n\t\t\t}\r\n\r\n\t\t\t// Check 4: Flag strings with multiple unordered placeholders (%s %s %s vs. %1$s %2$s %3$s)\r\n\t\t\tconst unorderedMatches =\r\n\t\t\t\ttranslation.msgid.match(this.UNORDERED_SPRINTF_PLACEHOLDER_REGEX) || [];\r\n\t\t\tconst unorderedMatchesCount = unorderedMatches.length;\r\n\r\n\t\t\tif (unorderedMatchesCount >= 2) {\r\n\t\t\t\tconst message = `Multiple placeholders should be ordered. ${location}`;\r\n\t\t\t\tthis.results.push(message);\r\n\t\t\t}\r\n\r\n\t\t\tif (translation.msgid_plural) {\r\n\t\t\t\tconst singlePlaceholders =\r\n\t\t\t\t\ttranslation.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX) || [];\r\n\t\t\t\tconst pluralPlaceholders =\r\n\t\t\t\t\ttranslation.msgid_plural.match(this.SPRINTF_PLACEHOLDER_REGEX) || [];\r\n\r\n\t\t\t\t// See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals\r\n\t\t\t\tif (singlePlaceholders.length < pluralPlaceholders.length) {\r\n\t\t\t\t\t// Check 5: Flag things like _n('One comment', '%s Comments')\r\n\t\t\t\t\tconst message = `Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals ${location}`;\r\n\t\t\t\t\tthis.results.push(message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Reordering is fine, but mismatched placeholders is probably wrong\r\n\t\t\t\t\tconst sortedSinglePlaceholders = [...singlePlaceholders].sort();\r\n\t\t\t\t\tconst sortedPluralPlaceholders = [...pluralPlaceholders].sort();\r\n\r\n\t\t\t\t\t// Check 6: Flag things like _n('%s Comment (%d)', '%s Comments (%s)')\r\n\t\t\t\t\tif (\r\n\t\t\t\t\t\tJSON.stringify(sortedSinglePlaceholders) !==\r\n\t\t\t\t\t\tJSON.stringify(sortedPluralPlaceholders)\r\n\t\t\t\t\t) {\r\n\t\t\t\t\t\tconst message = `Mismatched placeholders for singular and plural string. ${location}`;\r\n\t\t\t\t\t\tthis.results.push(message);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Get the results of the audit process\r\n\t * @returns An array of messages\r\n\t */\r\n\tpublic getResults(): string[] {\r\n\t\treturn this.results;\r\n\t}\r\n}\r\n\r\nexport default StringAuditor;\r\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { unlinkSync, writeFileSync } from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport type { Block, SetOfBlocks } from \"gettext-merger\";\r\nimport type { Args } from \"../types.js\";\r\n\r\nexport function audit(args: Args, translationsUnion: SetOfBlocks) {\r\n\t/** Run the audit process */\r\n\tconst auditor = new StringAuditor(args.domain);\r\n\tauditor.auditStrings(translationsUnion.blocks);\r\n\r\n\t/** Get and print the results of the audit process */\r\n\tconsole.log(\"Audit Complete!\");\r\n\tif (auditor.getResults().length === 0) {\r\n\t\tconsole.log(\"No issues found! \uD83C\uDF89\");\r\n\t\t// if there are no errors, we can remove the audit.log file\r\n\t\ttry {\r\n\t\t\tunlinkSync(path.join(args.paths.cwd, \"audit.log\"));\r\n\t\t} catch (_error) {\r\n\t\t\t//ignore\r\n\t\t}\r\n\t} else {\r\n\t\tconsole.log(`Found ${auditor.getResults().length} issues!`);\r\n\t\t// Print the results if not in silent mode\r\n\t\tif (args.options?.silent !== true) {\r\n\t\t\tconst results = auditor.getResults().join(\"\\n\");\r\n\t\t\tconsole.log(results);\r\n\t\t}\r\n\t\t/** Write the audit results to a file */\r\n\t\twriteFileSync(path.join(args.paths.cwd, \"audit.log\"), auditor.getResults().join(\"\\n\"));\r\n\t}\r\n}\r\n\r\n/**\r\n * Class to audit gettext strings\r\n *\r\n * Example usage:\r\n * const auditor = new StringAuditor('plugin');\r\n * auditor.auditStrings(translationBlocks);\r\n */\r\nclass StringAuditor {\r\n\tprivate readonly SPRINTF_PLACEHOLDER_REGEX =\r\n\t\t/%(?:\\d+\\$)?[+-]?(?:[ 0]|'.)?-?\\d*(?:\\.\\d+)?[bcdeEfFgGhHosuxX]/g;\r\n\tprivate readonly UNORDERED_SPRINTF_PLACEHOLDER_REGEX =\r\n\t\t/%(?!(\\d+)\\$)[+-]?(?:[ 0]|'.)?-?\\d*(?:\\.\\d+)?[bcdeEfFgGhHosuxX]/g;\r\n\tprivate projectType: string;\r\n\r\n\t/**\r\n\t * The results of the audit process\r\n\t */\r\n\tpublic results: string[] = [];\r\n\r\n\tconstructor(projectType: string) {\r\n\t\tthis.projectType = projectType;\r\n\t}\r\n\r\n\tprivate getFileHeaders(projectType: string): string[] {\r\n\t\t// Implement based on your requirements\r\n\t\t// This would be the equivalent of the PHP get_file_headers method\r\n\t\tconst headers: Record<string, string[]> = {\r\n\t\t\tplugin: [\r\n\t\t\t\t\"Plugin Name:\",\r\n\t\t\t\t\"Plugin URI:\",\r\n\t\t\t\t\"Description:\",\r\n\t\t\t\t\"Author:\",\r\n\t\t\t\t\"Author URI:\",\r\n\t\t\t\t\"Version:\",\r\n\t\t\t\t\"Text Domain:\",\r\n\t\t\t\t\"Domain Path:\",\r\n\t\t\t\t\"Network:\",\r\n\t\t\t\t\"Requires at least:\",\r\n\t\t\t\t\"Requires PHP:\",\r\n\t\t\t],\r\n\t\t\ttheme: [\r\n\t\t\t\t\"Theme Name:\",\r\n\t\t\t\t\"Theme URI:\",\r\n\t\t\t\t\"Author:\",\r\n\t\t\t\t\"Author URI:\",\r\n\t\t\t\t\"Description:\",\r\n\t\t\t\t\"Version:\",\r\n\t\t\t\t\"License:\",\r\n\t\t\t\t\"License URI:\",\r\n\t\t\t\t\"Text Domain:\",\r\n\t\t\t\t\"Domain Path:\",\r\n\t\t\t\t\"Tags:\",\r\n\t\t\t\t\"Requires at least:\",\r\n\t\t\t\t\"Requires PHP:\",\r\n\t\t\t],\r\n\t\t};\r\n\r\n\t\treturn headers[projectType] || [];\r\n\t}\r\n\r\n\tauditStrings(translations: Block[]): void {\r\n\t\tfor (const translation of translations) {\r\n\t\t\tconst references = translation.comments?.reference || [];\r\n\r\n\t\t\t// File headers don't have any file references\r\n\t\t\tconst location = references.length > 0 ? `(${references[0]})` : \"\";\r\n\r\n\t\t\t// Check 0: Flag strings without msgid is the header so it's not a translation and should be ignored\r\n\t\t\tif (!translation.msgid) {\r\n\t\t\t\tcontinue;\r\n\t\t\t}\r\n\r\n\t\t\t// Check 1: Flag strings with placeholders that should have translator comments\r\n\t\t\tif (\r\n\t\t\t\t(!translation.comments?.extracted ||\r\n\t\t\t\t\ttranslation.comments.extracted.length === 0) &&\r\n\t\t\t\t(translation.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX) || [])\r\n\t\t\t\t\t.length >= 1\r\n\t\t\t) {\r\n\t\t\t\tconst message = `The string \"${translation.msgid}\" contains placeholders but has no \"translators:\" comment to clarify their meaning. ${location}`;\r\n\t\t\t\tthis.results.push(message);\r\n\t\t\t}\r\n\r\n\t\t\t// Check 2: Flag strings with different translator comments\r\n\t\t\tif (\r\n\t\t\t\ttranslation.comments?.extracted &&\r\n\t\t\t\ttranslation.comments.extracted.length > 0\r\n\t\t\t) {\r\n\t\t\t\tlet comments = translation.comments.extracted;\r\n\r\n\t\t\t\t// Remove plugin header information from comments\r\n\t\t\t\tcomments = comments.filter((comment) => {\r\n\t\t\t\t\tfor (const fileHeader of this.getFileHeaders(this.projectType)) {\r\n\t\t\t\t\t\tif (comment.startsWith(fileHeader)) {\r\n\t\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tconst uniqueComments: string[] = [];\r\n\r\n\t\t\t\t// Remove duplicate comments\r\n\t\t\t\tcomments = comments.filter((comment) => {\r\n\t\t\t\t\tif (uniqueComments.includes(comment)) {\r\n\t\t\t\t\t\treturn false;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tuniqueComments.push(comment);\r\n\t\t\t\t\treturn true;\r\n\t\t\t\t});\r\n\r\n\t\t\t\tconst commentsCount = comments.length;\r\n\r\n\t\t\t\tif (commentsCount > 1) {\r\n\t\t\t\t\tconst message = `The string \"${translation.msgid}\" has ${commentsCount} different translator comments. ${location}\\n${comments.join(\"\\n\")}`;\r\n\t\t\t\t\tthis.results.push(message);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// Extract non-placeholder content from the string\r\n\t\t\tconst nonPlaceholderContent = translation.msgid\r\n\t\t\t\t.trim()\r\n\t\t\t\t.replace(/^(['\"])(.*)\\1$/s, \"$2\")\r\n\t\t\t\t.replace(this.SPRINTF_PLACEHOLDER_REGEX, \"\");\r\n\r\n\t\t\t// Check 3: Flag empty strings without any translatable content\r\n\t\t\tif (nonPlaceholderContent === \"\") {\r\n\t\t\t\tconst message = `Found string without translatable content. ${location}`;\r\n\t\t\t\tthis.results.push(message);\r\n\t\t\t}\r\n\r\n\t\t\t// Check 4: Flag strings with multiple unordered placeholders (%s %s %s vs. %1$s %2$s %3$s)\r\n\t\t\tconst unorderedMatches =\r\n\t\t\t\ttranslation.msgid.match(this.UNORDERED_SPRINTF_PLACEHOLDER_REGEX) || [];\r\n\t\t\tconst unorderedMatchesCount = unorderedMatches.length;\r\n\r\n\t\t\tif (unorderedMatchesCount >= 2) {\r\n\t\t\t\tconst message = `Multiple placeholders should be ordered. ${location}`;\r\n\t\t\t\tthis.results.push(message);\r\n\t\t\t}\r\n\r\n\t\t\tif (translation.msgid_plural) {\r\n\t\t\t\tconst singlePlaceholders =\r\n\t\t\t\t\ttranslation.msgid.match(this.SPRINTF_PLACEHOLDER_REGEX) || [];\r\n\t\t\t\tconst pluralPlaceholders =\r\n\t\t\t\t\ttranslation.msgid_plural.match(this.SPRINTF_PLACEHOLDER_REGEX) || [];\r\n\r\n\t\t\t\t// See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals\r\n\t\t\t\tif (singlePlaceholders.length < pluralPlaceholders.length) {\r\n\t\t\t\t\t// Check 5: Flag things like _n('One comment', '%s Comments')\r\n\t\t\t\t\tconst message = `Missing singular placeholder, needed for some languages. See https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/#plurals ${location}`;\r\n\t\t\t\t\tthis.results.push(message);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// Reordering is fine, but mismatched placeholders is probably wrong\r\n\t\t\t\t\tconst sortedSinglePlaceholders = [...singlePlaceholders].sort();\r\n\t\t\t\t\tconst sortedPluralPlaceholders = [...pluralPlaceholders].sort();\r\n\r\n\t\t\t\t\t// Check 6: Flag things like _n('%s Comment (%d)', '%s Comments (%s)')\r\n\t\t\t\t\tif (\r\n\t\t\t\t\t\tJSON.stringify(sortedSinglePlaceholders) !==\r\n\t\t\t\t\t\tJSON.stringify(sortedPluralPlaceholders)\r\n\t\t\t\t\t) {\r\n\t\t\t\t\t\tconst message = `Mismatched placeholders for singular and plural string. ${location}`;\r\n\t\t\t\t\t\tthis.results.push(message);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t/**\r\n\t * Get the results of the audit process\r\n\t * @returns An array of messages\r\n\t */\r\n\tpublic getResults(): string[] {\r\n\t\treturn this.results;\r\n\t}\r\n}\r\n\r\nexport default StringAuditor;\r\n"],
5
+ "mappings": "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",
6
6
  "names": ["path"]
7
7
  }