@atomicsmash/cli 2.1.1 → 3.1.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.
@@ -0,0 +1,3 @@
1
+ export declare const blocksHelpMessage = "\n Atomic Smash CLI - Blocks command.\n\n A command to generate WordPress blocks from a src folder.\n\n Options:\n --in The directory where the WP blocks can be found.\n --out The directory where the WP blocks will be output.\n\t\t--watch Watch the blocks in folder for changes and compile.\n\n Example usage:\n $ smash-cli blocks --watch --in src --out build\n";
2
+ export default function blocks(args: string[]): void;
3
+ //# sourceMappingURL=blocks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/commands/blocks.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,iBAAiB,+YAY7B,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QA+J5C"}
@@ -0,0 +1,223 @@
1
+ import crypto from "node:crypto";
2
+ import { readFileSync, writeFileSync, renameSync } from "node:fs";
3
+ import { readdir } from "node:fs/promises";
4
+ import { resolve as resolvePath, dirname as pathDirname } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import DependencyExtractionWebpackPlugin from "@wordpress/dependency-extraction-webpack-plugin";
7
+ import defaultConfig from "@wordpress/scripts/config/webpack.config.js";
8
+ import autoprefixer from "autoprefixer";
9
+ import cssnano from "cssnano";
10
+ import glob from "glob-promise";
11
+ import postcss from "postcss";
12
+ import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
13
+ import webpack from "webpack";
14
+ import { hasHelpFlag, toCamelCase } from "../utils.js";
15
+ // eslint-disable-next-line @typescript-eslint/naming-convention
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ // eslint-disable-next-line @typescript-eslint/naming-convention
18
+ const __dirname = pathDirname(__filename);
19
+ const isProduction = process.env.NODE_ENV === "production";
20
+ export const blocksHelpMessage = `
21
+ Atomic Smash CLI - Blocks command.
22
+
23
+ A command to generate WordPress blocks from a src folder.
24
+
25
+ Options:
26
+ --in The directory where the WP blocks can be found.
27
+ --out The directory where the WP blocks will be output.
28
+ --watch Watch the blocks in folder for changes and compile.
29
+
30
+ Example usage:
31
+ $ smash-cli blocks --watch --in src --out build
32
+ `;
33
+ export default function blocks(args) {
34
+ if (hasHelpFlag(args)) {
35
+ console.log(blocksHelpMessage);
36
+ return;
37
+ }
38
+ const inFlag = args[args.findIndex((arg) => arg === "--in") + 1];
39
+ if (!inFlag || inFlag.startsWith("--")) {
40
+ throw new Error("You need to provide a value for the --in flag.");
41
+ }
42
+ const outFlag = args[args.findIndex((arg) => arg === "--out") + 1];
43
+ if (!outFlag || outFlag.startsWith("--")) {
44
+ throw new Error("You need to provide a value for the --out flag.");
45
+ }
46
+ const srcFolder = resolvePath(inFlag);
47
+ const distFolder = resolvePath(outFlag);
48
+ const compiler = webpack({
49
+ ...defaultConfig,
50
+ entry: () => getAllBlocksJSEntryPoints(srcFolder),
51
+ plugins: [
52
+ ...(defaultConfig.plugins?.filter((plugin) => plugin.constructor.name !== "DependencyExtractionWebpackPlugin") ?? []),
53
+ new DependencyExtractionWebpackPlugin({
54
+ combineAssets: true,
55
+ }),
56
+ {
57
+ apply: (compiler) => {
58
+ compiler.hooks.afterEmit.tapPromise("Build CSS and copy to test area", async () => {
59
+ const plugins = [autoprefixer];
60
+ if (isProduction) {
61
+ plugins.push(cssnano({ preset: "default" }));
62
+ }
63
+ await glob
64
+ .promise(`${srcFolder}/blocks/**/*.css`)
65
+ .then(async (matches) => {
66
+ for (const match of matches) {
67
+ const fileName = match.split("/").pop();
68
+ if (!fileName) {
69
+ console.error(`Failed to get filename of ${match}`);
70
+ continue;
71
+ }
72
+ const css = readFileSync(match);
73
+ await postcss(plugins)
74
+ .process(css, {
75
+ from: match,
76
+ to: match.replace(srcFolder, distFolder),
77
+ })
78
+ .then((result) => {
79
+ writeFileSync(match.replace(srcFolder, distFolder), result.css);
80
+ if (result.map) {
81
+ writeFileSync(`${match.replace(srcFolder, distFolder)}.map`, result.map.toString());
82
+ }
83
+ });
84
+ }
85
+ })
86
+ .then(async () => {
87
+ if (!isProduction) {
88
+ return;
89
+ }
90
+ return glob
91
+ .promise(`${distFolder}/**/*.css`)
92
+ .then((matches) => {
93
+ for (const match of matches) {
94
+ const fileBuffer = readFileSync(match);
95
+ const contentHash = crypto.createHash("shake256", {
96
+ outputLength: 10,
97
+ });
98
+ contentHash.update(fileBuffer);
99
+ const fileMatchArray = match.split("/");
100
+ const newFileName = fileMatchArray
101
+ .pop()
102
+ ?.replace(".css", `.${contentHash.digest("hex")}.css`);
103
+ if (!newFileName || newFileName === "") {
104
+ throw new Error("Error getting CSS file name.");
105
+ }
106
+ renameSync(match, `${fileMatchArray.join("/")}/${newFileName}`);
107
+ }
108
+ return;
109
+ });
110
+ })
111
+ .catch((error) => {
112
+ console.error(error);
113
+ throw error;
114
+ });
115
+ });
116
+ },
117
+ },
118
+ ],
119
+ output: {
120
+ path: distFolder,
121
+ clean: true,
122
+ },
123
+ resolve: {
124
+ plugins: [new TsconfigPathsPlugin()],
125
+ extensions: [".ts", ".js", ".tsx", ".jsx"],
126
+ },
127
+ });
128
+ if (args.find((value) => value === "--watch")) {
129
+ const watching = compiler.watch({
130
+ // Example
131
+ aggregateTimeout: 300,
132
+ poll: undefined,
133
+ }, (error, stats) => {
134
+ if (error) {
135
+ console.error(error);
136
+ process.exitCode = 1;
137
+ watching.close((closeError) => {
138
+ console.error(closeError);
139
+ });
140
+ }
141
+ if (stats?.hasErrors()) {
142
+ for (const statError of stats.compilation.errors) {
143
+ console.error(statError.message);
144
+ }
145
+ }
146
+ });
147
+ process.on("SIGINT", function () {
148
+ watching.close((closeError) => {
149
+ console.error(closeError);
150
+ });
151
+ });
152
+ }
153
+ else {
154
+ compiler.run((error, stats) => {
155
+ if (error) {
156
+ console.error(error);
157
+ process.exitCode = 1;
158
+ }
159
+ if (stats?.hasErrors()) {
160
+ process.exitCode = 1;
161
+ }
162
+ compiler.close((closeError) => {
163
+ if (closeError) {
164
+ process.exitCode = 1;
165
+ }
166
+ });
167
+ });
168
+ }
169
+ }
170
+ async function getAllBlocksJSEntryPoints(srcFolder) {
171
+ const entryPoints = {
172
+ helpers: {
173
+ import: `${__dirname}/helpers.tsx`,
174
+ filename: `helpers${isProduction ? `.[contenthash]` : ""}.js`,
175
+ },
176
+ svgs: {
177
+ import: `${srcFolder}/svgs.tsx`,
178
+ filename: `svgs${isProduction ? `.[contenthash]` : ""}.js`,
179
+ },
180
+ };
181
+ const blockFolders = await readdir(`${srcFolder}/blocks`, {
182
+ withFileTypes: true,
183
+ }).then((srcDirFiles) => {
184
+ return srcDirFiles
185
+ .filter((dirent) => dirent.isDirectory())
186
+ .map((dirent) => dirent.name);
187
+ });
188
+ for (const block of blockFolders) {
189
+ const blockFiles = await readdir(`${srcFolder}/blocks/${block}`, {
190
+ withFileTypes: true,
191
+ }).then((blockDirFiles) => {
192
+ return blockDirFiles
193
+ .filter((file) => !file.isDirectory())
194
+ .map((file) => file.name)
195
+ .filter((file) => file.endsWith(".js") || file.endsWith(".ts"));
196
+ });
197
+ for (const blockJSFile of blockFiles) {
198
+ let blockBonusScriptNumber = 1;
199
+ const [filename] = blockJSFile.split(".");
200
+ let entryName;
201
+ if (filename === "index") {
202
+ entryName = block;
203
+ }
204
+ else if (filename === "editor") {
205
+ entryName = `${block}-editor`;
206
+ }
207
+ else if (filename === "view") {
208
+ entryName = `${block}-view`;
209
+ }
210
+ else {
211
+ entryName = `${block}-bonus${blockBonusScriptNumber}`;
212
+ blockBonusScriptNumber++;
213
+ }
214
+ entryPoints[toCamelCase(entryName)] = {
215
+ import: `${srcFolder}/blocks/${block}/${blockJSFile}`,
216
+ filename: `blocks/${block}/${filename}${isProduction ? `.[contenthash]` : ""}.js`,
217
+ };
218
+ }
219
+ }
220
+ // eslint-disable-next-line no-console
221
+ console.log({ entryPoints });
222
+ return entryPoints;
223
+ }
@@ -0,0 +1,3 @@
1
+ export declare const svgHelpMessage = "\n Atomic Smash CLI - SVG command.\n\n Generate an SVG sprite from a group of SVGs.\n\n Options:\n --in The directory where the SVGs can be found.\n --out The directory where the SVG sprite will be output.\n\n Example usage:\n $ smash-cli svg --in icons --out public/assets\n";
2
+ export default function svg(args: string[]): void;
3
+ //# sourceMappingURL=svg.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.d.ts","sourceRoot":"","sources":["../../src/commands/svg.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,cAAc,oTAW1B,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,QA6EzC"}
@@ -1,9 +1,9 @@
1
1
  import { readFileSync, mkdirSync, writeFileSync } from "node:fs";
2
2
  import { resolve as resolvePath, join as joinPath, dirname } from "path";
3
- import glob from "glob";
3
+ import glob from "glob-promise";
4
4
  import SVGSpriter from "svg-sprite";
5
5
  import File from "vinyl";
6
- import { hasHelpFlag } from "./../utils.js";
6
+ import { hasHelpFlag } from "../utils.js";
7
7
  export const svgHelpMessage = `
8
8
  Atomic Smash CLI - SVG command.
9
9
 
@@ -51,24 +51,38 @@ export default function svg(args) {
51
51
  const spriter = new SVGSpriter(config);
52
52
  const cwd = resolvePath(inFlag);
53
53
  // Find SVG files recursively via `glob`
54
- glob("**/*.svg", { cwd }, (error, files) => {
55
- files.forEach((file) => {
56
- // Create and add a vinyl file instance for each SVG
57
- spriter.add(new File({
58
- path: joinPath(cwd, file),
59
- base: cwd,
60
- contents: readFileSync(joinPath(cwd, file)), // SVG file contents
61
- }));
62
- });
63
- /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument */
64
- spriter.compile((error, result) => {
65
- for (const type in result.symbol) {
66
- mkdirSync(dirname(result.symbol[type].path), {
67
- recursive: true,
68
- });
69
- writeFileSync(result.symbol[type].path, result.symbol[type].contents);
70
- }
54
+ glob("**/*.svg", { cwd })
55
+ .then(async (files) => {
56
+ await new Promise((resolve) => {
57
+ files.forEach((file) => {
58
+ // Create and add a vinyl file instance for each SVG
59
+ spriter.add(new File({
60
+ path: joinPath(cwd, file),
61
+ base: cwd,
62
+ contents: readFileSync(joinPath(cwd, file)), // SVG file contents
63
+ }));
64
+ });
65
+ resolve();
66
+ })
67
+ .then(async () => {
68
+ await spriter
69
+ .compileAsync()
70
+ .then((compiledResponse) => {
71
+ const { result } = compiledResponse;
72
+ for (const type of Object.values(result.symbol)) {
73
+ if (type.contents) {
74
+ mkdirSync(dirname(type.path), { recursive: true });
75
+ writeFileSync(type.path, type.contents.toString());
76
+ }
77
+ }
78
+ });
79
+ })
80
+ .then(() => {
81
+ console.log(`SVG sprite was successfully generated in ${outFlag}.`);
71
82
  });
83
+ })
84
+ .catch((error) => {
85
+ console.error({ error });
86
+ throw error;
72
87
  });
73
- console.log(`SVG sprite was successfully generated in ${outFlag}.`);
74
88
  }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js CHANGED
@@ -19,8 +19,9 @@ switch (commandArg) {
19
19
  console.log(packageJson.version);
20
20
  break;
21
21
  case "svg":
22
+ case "blocks":
22
23
  try {
23
- await import(`./cli/${commandArg}.js`).then((module) => module.default(process.argv.slice(3)));
24
+ await import(`./commands/${commandArg}.js`).then((module) => module.default(process.argv.slice(3)));
24
25
  }
25
26
  catch (error) {
26
27
  if (error instanceof Error) {
@@ -0,0 +1,3 @@
1
+ export declare const helpMessage = "\n Atomic Smash CLI.\n\n Available commands:\n svg - generate an SVG sprite from a group of SVGs.\n\n Options:\n --help, -h Print a help message for the command and exit.\n --version, -v Print the CLI version and exit.\n --debug Show NodeJS debugging information for errors.\n";
2
+ export declare const noCommandFound: string;
3
+ //# sourceMappingURL=messages.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,mUAUvB,CAAC;AAEF,eAAO,MAAM,cAAc,QAE1B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function setup(): Promise<void>;
2
+ export declare function teardown(): Promise<void>;
3
+ //# sourceMappingURL=test-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-setup.d.ts","sourceRoot":"","sources":["../src/test-setup.ts"],"names":[],"mappings":"AAgCA,wBAAsB,KAAK,kBAkB1B;AAED,wBAAsB,QAAQ,kBAS7B"}
@@ -0,0 +1,44 @@
1
+ import { unlink, writeFile } from "node:fs";
2
+ import { resolve as resolvePath, dirname as pathDirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { execute, packageJson } from "./utils";
5
+ const packageName = packageJson.name;
6
+ const packageVersion = packageJson.version;
7
+ function isValidPackageName(packageName) {
8
+ return !!packageName;
9
+ }
10
+ function isValidPackageVersion(packageVersion) {
11
+ return !!packageVersion;
12
+ }
13
+ if (!isValidPackageName(packageName) ||
14
+ !isValidPackageVersion(packageVersion)) {
15
+ throw new Error("Invalid package, must have name and version");
16
+ }
17
+ const packName = `${packageName
18
+ .replaceAll("@", "")
19
+ .replaceAll(`/`, "-")}-${packageVersion}.tgz`;
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ // eslint-disable-next-line @typescript-eslint/naming-convention
23
+ const __dirname = pathDirname(__filename);
24
+ export async function setup() {
25
+ console.log("Packing a test version...");
26
+ await execute(`cd ${resolvePath(__dirname, "../")} && ls && npm pack --pack-destination ${__dirname}/tests/artifacts`);
27
+ console.log(`Install test package...`);
28
+ writeFile(`${__dirname}/tests/package.json`, "{}", (err) => {
29
+ if (err) {
30
+ console.log("writeFile failed");
31
+ throw err;
32
+ }
33
+ });
34
+ await execute(`cd ${__dirname}/tests && npm pkg set dependencies.@atomicsmash/cli=file:${__dirname}/tests/artifacts/${packName} && npm install`);
35
+ }
36
+ export async function teardown() {
37
+ console.log("Deleting test package...");
38
+ unlink(`${__dirname}/tests/artifacts/${packName}`, (err) => {
39
+ if (err)
40
+ throw err;
41
+ });
42
+ console.log("Deleting node modules...");
43
+ await execute(`cd ${__dirname}/tests && rm -rf node_modules package.json package-lock.json`);
44
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=main.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.test.d.ts","sourceRoot":"","sources":["../../src/tests/main.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,48 @@
1
+ import { expect, test, describe } from "vitest";
2
+ import { execute } from "../utils";
3
+ import { helpMessage, noCommandFound } from "./../messages.js";
4
+ import { testCommand, packageVersion } from "./../utils.js";
5
+ describe.concurrent("Base CLI helpers work as intended", () => {
6
+ test("main cli shows help message if nothing is added after main command", async () => {
7
+ await expect(execute(`${testCommand}`)).resolves.toEqual({
8
+ error: null,
9
+ stdout: `${helpMessage}\n`,
10
+ stderr: "",
11
+ });
12
+ });
13
+ test("main cli shows help message if --help is added after main command", async () => {
14
+ await expect(execute(`${testCommand} --help`)).resolves.toEqual({
15
+ error: null,
16
+ stdout: `${helpMessage}\n`,
17
+ stderr: "",
18
+ });
19
+ });
20
+ test("main cli shows help message if -h is added after main command", async () => {
21
+ await expect(execute(`${testCommand} -h`)).resolves.toEqual({
22
+ error: null,
23
+ stdout: `${helpMessage}\n`,
24
+ stderr: "",
25
+ });
26
+ });
27
+ test("main cli shows command not found message if invalid command is provided", async () => {
28
+ await expect(execute(`${testCommand} fake-command`)).rejects.toEqual({
29
+ error: new Error(`Command failed: ${testCommand} fake-command\n${noCommandFound}\n`),
30
+ stdout: "",
31
+ stderr: `${noCommandFound}\n`,
32
+ });
33
+ });
34
+ test("main cli shows correct version number if --version is added after main command", async () => {
35
+ await expect(execute(`${testCommand} --version`)).resolves.toEqual({
36
+ error: null,
37
+ stdout: `${packageVersion}\n`,
38
+ stderr: "",
39
+ });
40
+ });
41
+ test("main cli shows correct version number if -v is added after main command", async () => {
42
+ await expect(execute(`${testCommand} -v`)).resolves.toEqual({
43
+ error: null,
44
+ stdout: `${packageVersion}\n`,
45
+ stderr: "",
46
+ });
47
+ });
48
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=svg.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svg.test.d.ts","sourceRoot":"","sources":["../../src/tests/svg.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,60 @@
1
+ import { existsSync, unlink, readFileSync } from "node:fs";
2
+ import { resolve as resolvePath, dirname as pathDirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { expect, test, describe, afterAll } from "vitest";
5
+ import { svgHelpMessage } from "../commands/svg";
6
+ import { testCommand, execute } from "../utils";
7
+ // eslint-disable-next-line @typescript-eslint/naming-convention
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ // eslint-disable-next-line @typescript-eslint/naming-convention
10
+ const __dirname = pathDirname(__filename);
11
+ const testSVGsIn = resolvePath(__dirname, "./svg/in");
12
+ const testSVGsOut = resolvePath(__dirname, "./svg/out");
13
+ describe("SVG command works as intended", () => {
14
+ test("svg command correctly displays help message", async () => {
15
+ await expect(execute(`${testCommand} svg --help`)).resolves.toEqual({
16
+ error: null,
17
+ stdout: `${svgHelpMessage}\n`,
18
+ stderr: "",
19
+ });
20
+ });
21
+ test("svg command correctly displays --in flag missing error if no flags added", async () => {
22
+ const command = `${testCommand} svg`;
23
+ await expect(execute(command)).rejects.toEqual({
24
+ error: new Error(`Command failed: ${command}\nError: You need to provide a value for the --in flag.\n`),
25
+ stdout: "",
26
+ stderr: "Error: You need to provide a value for the --in flag.\n",
27
+ });
28
+ });
29
+ test("svg command correctly displays --in flag missing error if in flag is missing", async () => {
30
+ const command = `${testCommand} svg --out ${testSVGsOut}`;
31
+ await expect(execute(command)).rejects.toEqual({
32
+ error: new Error(`Command failed: ${command}\nError: You need to provide a value for the --in flag.\n`),
33
+ stdout: "",
34
+ stderr: "Error: You need to provide a value for the --in flag.\n",
35
+ });
36
+ });
37
+ test("svg command correctly displays --out flag missing error if out flag is missing", async () => {
38
+ const command = `${testCommand} svg --in ${testSVGsIn}`;
39
+ await expect(execute(command)).rejects.toEqual({
40
+ error: new Error(`Command failed: ${command}\nError: You need to provide a value for the --out flag.\n`),
41
+ stdout: "",
42
+ stderr: "Error: You need to provide a value for the --out flag.\n",
43
+ });
44
+ });
45
+ test("svg command produces the correct svg output", async () => {
46
+ await execute(`${testCommand} svg --in ${testSVGsIn} --out ${testSVGsOut}`);
47
+ expect(existsSync(`${testSVGsOut}/sprite.svg`)).toBe(true);
48
+ expect(readFileSync(`${testSVGsOut}/sprite.svg`, "utf8")).toBe(
49
+ // spellchecker: disable-next-line
50
+ '<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><symbol fill="none" viewBox="0 0 25 24" id="ArrowRight" xmlns="http://www.w3.org/2000/svg"><path d="M24.707 12.707a1 1 0 0 0 0-1.414l-6.364-6.364a1 1 0 1 0-1.414 1.414L22.586 12l-5.657 5.657a1 1 0 0 0 1.414 1.414l6.364-6.364ZM0 13h24v-2H0v2Z" fill="currentColor"/></symbol><symbol fill="none" viewBox="0 0 51 30" id="CardMastercard" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#ba)"><path d="M12.996 29.934v-1.99c0-.762-.463-1.261-1.26-1.261-.397 0-.83.131-1.127.564-.232-.363-.564-.564-1.063-.564-.332 0-.664.1-.927.464v-.398h-.695v3.185h.695v-1.759c0-.564.298-.83.761-.83.464 0 .696.297.696.83v1.76h.695v-1.76c0-.564.332-.83.761-.83.464 0 .695.297.695.83v1.76h.77Zm10.315-3.185h-1.128v-.963h-.695v.963h-.63v.63h.63v1.461c0 .73.297 1.16 1.093 1.16.297 0 .63-.1.861-.232l-.2-.6c-.201.132-.433.167-.6.167-.331 0-.463-.201-.463-.53V27.38h1.128v-.63h.004Zm5.903-.07a.943.943 0 0 0-.83.464v-.398h-.696v3.185h.696v-1.793c0-.53.231-.832.664-.832.131 0 .297.035.433.066l.2-.665c-.139-.027-.336-.027-.467-.027Zm-8.92.333c-.332-.232-.796-.333-1.294-.333-.796 0-1.325.398-1.325 1.029 0 .53.398.83 1.093.927l.332.035c.363.066.564.166.564.333 0 .232-.266.398-.73.398-.464 0-.83-.166-1.062-.333l-.333.53c.364.267.862.398 1.36.398.927 0 1.46-.433 1.46-1.028 0-.565-.432-.862-1.093-.963l-.332-.035c-.297-.034-.53-.1-.53-.297 0-.232.233-.364.6-.364.397 0 .795.166.996.267l.294-.564Zm18.5-.333a.943.943 0 0 0-.83.464v-.398h-.695v3.185h.695v-1.793c0-.53.232-.832.665-.832.131 0 .297.035.433.066l.2-.657c-.135-.035-.332-.035-.467-.035Zm-8.884 1.663c0 .962.664 1.658 1.692 1.658.463 0 .795-.1 1.128-.363l-.333-.565c-.266.201-.529.298-.83.298-.564 0-.962-.398-.962-1.029 0-.599.398-.997.962-1.028.297 0 .564.1.83.298l.333-.565c-.333-.266-.665-.363-1.128-.363-1.028-.004-1.692.696-1.692 1.659Zm6.432 0v-1.593h-.696v.398c-.231-.298-.564-.464-.996-.464-.897 0-1.592.696-1.592 1.659 0 .962.695 1.658 1.592 1.658.463 0 .796-.166.996-.464v.398h.696v-1.593Zm-2.554 0c0-.565.363-1.029.962-1.029.564 0 .962.433.962 1.029 0 .564-.398 1.028-.962 1.028-.595-.035-.962-.468-.962-1.029Zm-8.321-1.663c-.927 0-1.592.665-1.592 1.659 0 .997.665 1.658 1.627 1.658.463 0 .927-.131 1.294-.433l-.332-.499a1.578 1.578 0 0 1-.928.333c-.432 0-.861-.201-.962-.762h2.353v-.266c.031-1.025-.568-1.69-1.46-1.69Zm0 .6c.432 0 .73.266.796.76h-1.658c.066-.428.363-.76.862-.76Zm17.276 1.063v-2.854h-.695v1.659c-.232-.298-.564-.464-.997-.464-.896 0-1.592.696-1.592 1.659 0 .962.696 1.658 1.592 1.658.464 0 .796-.166.997-.464v.398h.695v-1.593Zm-2.553 0c0-.565.363-1.029.962-1.029.563 0 .961.433.961 1.029 0 .564-.398 1.028-.962 1.028-.598-.035-.962-.468-.962-1.029Zm-23.28 0v-1.593h-.696v.398c-.231-.298-.564-.464-.996-.464-.897 0-1.592.696-1.592 1.659 0 .962.695 1.658 1.592 1.658.463 0 .795-.166.996-.464v.398h.696v-1.593Zm-2.585 0c0-.565.363-1.029.962-1.029.564 0 .962.433.962 1.029 0 .564-.398 1.028-.962 1.028-.599-.035-.962-.468-.962-1.029Z" fill="#000"/><path d="M30.509 2.555H20.062v18.781H30.51V2.556Z" fill="#FF5A00"/><path d="M20.758 11.946c0-3.816 1.792-7.202 4.543-9.39A11.868 11.868 0 0 0 17.937 0C11.34 0 6 5.343 6 11.946s5.339 11.946 11.937 11.946c2.786 0 5.34-.963 7.364-2.556a11.925 11.925 0 0 1-4.543-9.39Z" fill="#EB001B"/><path d="M44.602 11.946c0 6.603-5.34 11.946-11.938 11.946-2.785 0-5.339-.963-7.363-2.556a11.884 11.884 0 0 0 4.543-9.39c0-3.816-1.793-7.202-4.543-9.39A11.849 11.849 0 0 1 32.66 0C39.262 0 44.6 5.378 44.6 11.946Z" fill="#F79E1B"/></g><defs><clipPath id="ba"><path fill="#fff" transform="translate(.5)" d="M0 0h50v30H0z"/></clipPath></defs></symbol><symbol fill="none" viewBox="0 0 24 24" id="Thumbtack" xmlns="http://www.w3.org/2000/svg"><path d="m15.115 10.155-.057-.748.057.748c.83-.063 3.136-.024 5.457 1.971l-8.446 8.446c-1.995-2.32-2.034-4.628-1.97-5.457a1.615 1.615 0 0 0-.455-1.267l-2.183-2.184a1.5 1.5 0 0 0-1.866-.205l-1.636 1.042-1.455-1.455 8.485-8.485L12.5 4.015l-1.042 1.637a1.5 1.5 0 0 0 .205 1.866L13.848 9.7c.354.355.833.487 1.267.454Z" stroke="currentColor" stroke-width="1.5"/><mask id="ca" fill="currentColor"><path d="m15.287 16.35 1.06-1.062 4.546 4.546.228 1.288-1.288-.227-4.546-4.546Z"/></mask><path d="m15.287 16.35 1.06-1.062 4.546 4.546.228 1.288-1.288-.227-4.546-4.546Z" fill="currentColor"/><path d="m15.287 16.35-1.06-1.062-1.061 1.061 1.06 1.06 1.061-1.06Zm1.06-1.062 1.061-1.06-1.06-1.06-1.06 1.06 1.06 1.06Zm4.546 4.546 1.478-.26-.082-.466-.335-.335-1.06 1.061Zm-1.06 1.06-1.06 1.062.334.334.465.082.26-1.477Zm1.288.228-.26 1.477 2.11.373-.373-2.11-1.477.26Zm-4.773-3.712 1.06-1.06-2.12-2.122-1.062 1.06 2.122 2.122Zm-1.06-1.06 4.545 4.545 2.121-2.122-4.546-4.545-2.12 2.121Zm5.605 3.484-4.545-4.545-2.122 2.12 4.546 4.547 2.122-2.122Zm-1.477.26.228 1.289 2.954-.522-.227-1.288-2.955.522Zm1.965-.45-1.288-.226-.52 2.954 1.287.227.521-2.954Z" mask="url(#ca)"/></symbol></svg>');
51
+ });
52
+ afterAll(() => {
53
+ // Delete sprite once all tests are complete to avoid false positives on subsequent tests
54
+ unlink(`${testSVGsOut}/sprite.svg`, (err) => {
55
+ if (err)
56
+ throw err;
57
+ console.log("Successfully deleted sprite.svg");
58
+ });
59
+ });
60
+ });
@@ -0,0 +1,14 @@
1
+ import type { ExecException } from "node:child_process";
2
+ import type { PackageJson } from "type-fest";
3
+ export declare const packageJson: PackageJson;
4
+ export declare const mainCommand: string;
5
+ export declare const testCommand: string;
6
+ export declare const packageVersion: string;
7
+ export declare function hasHelpFlag(args: string[]): boolean;
8
+ export declare function execute(command: string): Promise<{
9
+ error: ExecException | null;
10
+ stdout: string;
11
+ stderr: string;
12
+ }>;
13
+ export declare function toCamelCase(text: string): string;
14
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAY7C,eAAO,MAAM,WAAW,aAA4C,CAAC;AAIrE,eAAO,MAAM,WAAW,QAAkC,CAAC;AAC3D,eAAO,MAAM,WAAW,QAAwD,CAAC;AAIjF,eAAO,MAAM,cAAc,QAAsB,CAAC;AAElD,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,WAEzC;AAED,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM;WAEpC,aAAa,GAAG,IAAI;YACnB,MAAM;YACN,MAAM;GAUf;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,UAQvC"}
package/dist/utils.js CHANGED
@@ -1,11 +1,18 @@
1
1
  import { exec } from "node:child_process";
2
2
  import { createRequire } from "node:module";
3
+ import { dirname as pathDirname } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ // eslint-disable-next-line @typescript-eslint/naming-convention
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ // eslint-disable-next-line @typescript-eslint/naming-convention
8
+ const __dirname = pathDirname(__filename);
3
9
  const require = createRequire(import.meta.url);
4
10
  export const packageJson = require("../package.json");
5
11
  if (packageJson.bin === undefined) {
6
12
  throw new Error("Script name is not defined.");
7
13
  }
8
14
  export const mainCommand = Object.keys(packageJson.bin)[0];
15
+ export const testCommand = `${__dirname}/tests/node_modules/.bin/${mainCommand}`;
9
16
  if (!packageJson.version) {
10
17
  throw new Error("Package has no version number set.");
11
18
  }
@@ -17,9 +24,17 @@ export async function execute(command) {
17
24
  return new Promise((resolve, reject) => {
18
25
  exec(command, (error, stdout, stderr) => {
19
26
  if (error) {
27
+ console.error({ error, stdout, stderr });
20
28
  reject({ error, stdout, stderr });
21
29
  }
22
30
  resolve({ error, stdout, stderr });
23
31
  });
24
32
  });
25
33
  }
34
+ export function toCamelCase(text) {
35
+ return text.replace(/^([A-Z])|[\s-_](\w)/g, function (match, p1, p2) {
36
+ if (p2)
37
+ return p2.toUpperCase();
38
+ return p1.toLowerCase();
39
+ });
40
+ }