Skip to content

Commit 7aae11b

Browse files
committed
Centralize the definitions of common widget paths
1 parent 9b75666 commit 7aae11b

11 files changed

Lines changed: 123 additions & 97 deletions

File tree

packages/pluggable-widgets-tools/bin/mx-scripts.js

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#! /usr/bin/env node
22
const { execSync, spawnSync } = require("child_process");
33
const { existsSync } = require("fs");
4-
const { delimiter, dirname, join, parse } = require("path");
4+
const { delimiter, join, parse } = require("path");
55
const { checkMigration } = require("../utils/migration");
66
const { checkForEnzymeUsage } = require("../dist/utils/enzyme-detector");
77
const { red, blue, bold, whiteBright } = require("ansi-colors");
88
const semver = require("semver");
9-
const { auditPluggableWidgetsTools } = require("../dist/commands/audit");
9+
const { auditPluggableWidgetsTools } = require("../dist/commands/audit.js");
10+
const { prettierConfigPath } = require("../dist/utils/formatting.js");
11+
const { toolsRoot, widgetRoot } = require("../dist/widget/paths.js");
1012

1113
checkNodeVersion();
1214
(async () => {
@@ -16,10 +18,7 @@ checkNodeVersion();
1618
console.log(red("An error occurred while checking migration dependencies: ", e));
1719
}
1820

19-
const [, currentScriptPath, cmd, ...args] = process.argv;
20-
const toolsRoot = currentScriptPath.endsWith("pluggable-widgets-tools")
21-
? join(dirname(currentScriptPath), "../@mendix/pluggable-widgets-tools")
22-
: join(dirname(currentScriptPath), "..");
21+
const [, , cmd, ...args] = process.argv;
2322

2423
if (args.indexOf("--subprojectPath") > -1) {
2524
args.splice(args.indexOf("--subprojectPath"), 2);
@@ -46,7 +45,7 @@ checkNodeVersion();
4645
const commandWithArgs = realCommand + " " + args.join(" ");
4746
for (const subCommand of commandWithArgs.split(/&&/g)) {
4847
const result = spawnSync(subCommand.trim(), [], {
49-
cwd: process.cwd(),
48+
cwd: widgetRoot,
5049
env: {
5150
...process.env,
5251
PATH: [process.env.PATH].concat(nodeModulesBins).join(delimiter),
@@ -64,10 +63,8 @@ checkNodeVersion();
6463
}
6564
})();
6665

67-
function getRealCommand(cmd, toolsRoot) {
66+
function getRealCommand(cmd) {
6867
const eslintCommand = "eslint --config .eslintrc.js --ext .jsx,.js,.ts,.tsx src";
69-
const prettierConfigRootPath = join(__dirname, "../../../prettier.config.js");
70-
const prettierConfigPath = existsSync(prettierConfigRootPath) ? prettierConfigRootPath : "prettier.config.js";
7168
const prettierCommand = `prettier --config "${prettierConfigPath}" "{src,typings,tests}/**/*.{js,jsx,ts,tsx,scss}"`;
7269
const rollupCommandWeb = `rollup --config "${join(toolsRoot, "configs/rollup.config.mjs")}"`;
7370
const rollupCommandNative = `rollup --config "${join(toolsRoot, "configs/rollup.config.native.mjs")}"`;
@@ -147,7 +144,7 @@ function findNodeModulesBin() {
147144
}
148145

149146
function checkNodeVersion() {
150-
const packageJson = require(join(__dirname, "../package.json"));
147+
const packageJson = require(join(toolsRoot, "./package.json"));
151148
const nodeRange = new semver.Range(packageJson.engines.node);
152149

153150
console.log("Checking node and npm version...");

packages/pluggable-widgets-tools/configs/rollup.config.mjs

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,21 @@ import postcss from "rollup-plugin-postcss";
2020
import terser from "@rollup/plugin-terser";
2121
import shelljs from "shelljs";
2222
import { widgetTyping } from "./rollup-plugin-widget-typing.mjs";
23-
import {
24-
editorConfigEntry,
25-
isTypescript,
26-
previewEntry,
27-
projectPath,
28-
sourcePath,
29-
widgetEntry,
30-
widgetName,
31-
widgetPackage,
32-
widgetVersion,
33-
onwarn
34-
} from "./shared.mjs";
23+
import { editorConfigEntry, isTypescript, previewEntry, projectPath, widgetEntry, onwarn } from "./shared.mjs";
3524
import { copyLicenseFile, createMpkFile, licenseCustomTemplate } from "./helpers/rollup-helper.mjs";
3625
import url from "./rollup-plugin-assets.mjs";
26+
import { widgetName, widgetOrganization, widgetVersion } from "../dist/widget/package.js";
27+
import { widgetRoot } from "../dist/widget/paths.js";
3728

3829
const { loadConfigFile } = rollupLoadConfigFile;
3930
const { cp } = shelljs;
4031

41-
const outDir = join(sourcePath, "/dist/tmp/widgets/");
42-
const outWidgetDir = join(widgetPackage.replace(/\./g, "/"), widgetName.toLowerCase());
32+
const outDir = join(widgetRoot, "/dist/tmp/widgets/");
33+
const outWidgetDir = join(widgetOrganization.replace(/\./g, "/"), widgetName.toLowerCase());
4334
const outWidgetFile = join(outWidgetDir, `${widgetName}`);
4435
const absoluteOutPackageDir = join(outDir, outWidgetDir);
45-
const mpkDir = join(sourcePath, "dist", widgetVersion);
46-
const mpkFile = join(mpkDir, process.env.MPKOUTPUT ? process.env.MPKOUTPUT : `${widgetPackage}.${widgetName}.mpk`);
36+
const mpkDir = join(widgetRoot, "dist", widgetVersion);
37+
const mpkFile = join(mpkDir, process.env.MPKOUTPUT ? process.env.MPKOUTPUT : `${widgetOrganization}.${widgetName}.mpk`);
4738
const assetsDirName = "assets";
4839
const absoluteOutAssetsDir = join(absoluteOutPackageDir, assetsDirName);
4940
const outAssetsDir = join(outWidgetDir, assetsDirName);
@@ -208,8 +199,8 @@ export default async args => {
208199
});
209200
}
210201

211-
const customConfigPathJS = join(sourcePath, "rollup.config.js");
212-
const customConfigPathESM = join(sourcePath, "rollup.config.mjs");
202+
const customConfigPathJS = join(widgetRoot, "rollup.config.js");
203+
const customConfigPathESM = join(widgetRoot, "rollup.config.mjs");
213204
const existingConfigPath = existsSync(customConfigPathJS)
214205
? customConfigPathJS
215206
: existsSync(customConfigPathESM)
@@ -300,7 +291,7 @@ export default async args => {
300291
// configs affected by a change => we cannot know in advance which one will be "the last".
301292
// So we run the same logic for all configs, letting the last one win.
302293
command([
303-
async () => config.licenses && copyLicenseFile(sourcePath, outDir),
294+
async () => config.licenses && copyLicenseFile(widgetRoot, outDir),
304295
async () =>
305296
createMpkFile({
306297
mpkDir,
@@ -316,7 +307,7 @@ export default async args => {
316307

317308
function getClientComponentPlugins() {
318309
return [
319-
isTypescript ? widgetTyping({ sourceDir: join(sourcePath, "src") }) : null,
310+
isTypescript ? widgetTyping({ sourceDir: join(widgetRoot, "src") }) : null,
320311
clear({ targets: [outDir, mpkDir] }),
321312
command([
322313
() => {

packages/pluggable-widgets-tools/configs/rollup.config.native.mjs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,18 @@ import terser from "@rollup/plugin-terser";
1616
import shelljs from "shelljs";
1717
import { widgetTyping } from "./rollup-plugin-widget-typing.mjs";
1818
import { collectDependencies } from "./rollup-plugin-collect-dependencies.mjs";
19-
import {
20-
editorConfigEntry,
21-
isTypescript,
22-
projectPath,
23-
sourcePath,
24-
widgetEntry,
25-
widgetName,
26-
widgetPackage,
27-
widgetVersion,
28-
onwarn
29-
} from "./shared.mjs";
19+
import { editorConfigEntry, isTypescript, projectPath, widgetEntry, onwarn } from "./shared.mjs";
3020
import { copyLicenseFile, createMpkFile, licenseCustomTemplate } from "./helpers/rollup-helper.mjs";
21+
import { widgetName, widgetOrganization, widgetVersion } from "../dist/widget/package.js";
22+
import { widgetRoot } from "../dist/widget/paths.js";
3123

3224
const { cp } = shelljs;
3325
const { blue } = colors;
3426

35-
const outDir = join(sourcePath, "/dist/tmp/widgets/");
36-
const outWidgetFile = join(widgetPackage.replace(/\./g, "/"), widgetName.toLowerCase(), `${widgetName}`);
37-
const mpkDir = join(sourcePath, "dist", widgetVersion);
38-
const mpkFile = join(mpkDir, process.env.MPKOUTPUT ? process.env.MPKOUTPUT : `${widgetPackage}.${widgetName}.mpk`);
27+
const outDir = join(widgetRoot, "/dist/tmp/widgets/");
28+
const outWidgetFile = join(widgetOrganization.replace(/\./g, "/"), widgetName.toLowerCase(), `${widgetName}`);
29+
const mpkDir = join(widgetRoot, "dist", widgetVersion);
30+
const mpkFile = join(mpkDir, process.env.MPKOUTPUT ? process.env.MPKOUTPUT : `${widgetOrganization}.${widgetName}.mpk`);
3931

4032
const extensions = [".js", ".jsx", ".tsx", ".ts"];
4133

@@ -161,8 +153,8 @@ export default async args => {
161153
});
162154
}
163155

164-
const customConfigPathJS = join(sourcePath, "rollup.config.js");
165-
const customConfigPathESM = join(sourcePath, "rollup.config.mjs");
156+
const customConfigPathJS = join(widgetRoot, "rollup.config.js");
157+
const customConfigPathESM = join(widgetRoot, "rollup.config.mjs");
166158
const existingConfigPath = existsSync(customConfigPathJS)
167159
? customConfigPathJS
168160
: existsSync(customConfigPathESM)
@@ -237,7 +229,7 @@ export default async args => {
237229
// configs affected by a change => we cannot know in advance which one will be "the last".
238230
// So we run the same logic for all configs, letting the last one win.
239231
command([
240-
async () => config.licenses && copyLicenseFile(sourcePath, outDir),
232+
async () => config.licenses && copyLicenseFile(widgetRoot, outDir),
241233
async () =>
242234
createMpkFile({
243235
mpkDir,
@@ -253,7 +245,7 @@ export default async args => {
253245

254246
function getClientComponentPlugins() {
255247
return [
256-
isTypescript ? widgetTyping({ sourceDir: join(sourcePath, "src") }) : null,
248+
isTypescript ? widgetTyping({ sourceDir: join(widgetRoot, "src") }) : null,
257249
clear({ targets: [outDir, mpkDir] }),
258250
command([
259251
() => {

packages/pluggable-widgets-tools/configs/shared.mjs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { existsSync, readdirSync, promises as fs, readFileSync } from "node:fs";
1+
import { existsSync, readdirSync, promises as fs } from "node:fs";
22
import { join, relative } from "node:path";
33
import { config } from "dotenv";
44
import colors from "ansi-colors";
5-
import { throwOnIllegalChars, throwOnNoMatch } from "../dist/utils/validation.js";
5+
import { dir as sourcePath, widgetName, json } from "../dist/widget/package.js";
66

7-
config({ path: join(process.cwd(), ".env"), quiet: true });
7+
config({ path: join(sourcePath, ".env"), quiet: true });
88

99
export async function listDir(path) {
1010
const entries = await fs.readdir(path, { withFileTypes: true });
@@ -14,20 +14,6 @@ export async function listDir(path) {
1414
.concat(...(await Promise.all(entries.filter(e => e.isDirectory()).map(e => listDir(join(path, e.name))))));
1515
}
1616

17-
export const sourcePath = process.cwd();
18-
19-
const widgetPackageJson = JSON.parse(readFileSync(join(sourcePath, "package.json")));
20-
export const widgetName = widgetPackageJson.widgetName;
21-
export const widgetPackage = widgetPackageJson.packagePath;
22-
export const widgetVersion = widgetPackageJson.version;
23-
if (!widgetName || !widgetPackageJson) {
24-
throw new Error("Widget does not define widgetName in its package.json");
25-
}
26-
27-
throwOnIllegalChars(widgetName, "a-zA-Z", "The `widgetName` property in package.json");
28-
throwOnIllegalChars(widgetPackage, "a-zA-Z0-9_.-", "The `packagePath` property in package.json");
29-
throwOnNoMatch(widgetPackage, /^([a-zA-Z0-9_-]+.)*[a-zA-Z0-9_-]+$/, "The `packagePath` property in package.json");
30-
3117
const widgetSrcFiles = readdirSync(join(sourcePath, "src")).map(file => join(sourcePath, "src", file));
3218
export const widgetEntry = widgetSrcFiles.filter(file =>
3319
file.match(new RegExp(`[/\\\\]${escape(widgetName)}\\.[jt]sx?$`, "i"))
@@ -47,7 +33,7 @@ export const isTypescript = [widgetEntry, editorConfigEntry, previewEntry].some(
4733

4834
export const projectPath = [
4935
process.env.MX_PROJECT_PATH,
50-
widgetPackageJson.config.projectPath,
36+
json.config.projectPath,
5137
join(sourcePath, "tests/testProject")
5238
].filter(path => path && existsSync(path))[0];
5339

packages/pluggable-widgets-tools/src/commands/audit.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { exec } from "node:child_process";
55
import { maxSatisfying, minSatisfying } from "semver";
66
import { confirm } from "../cli/confirm";
77
import { readFile, writeFile } from "node:fs";
8-
import { join } from "node:path";
8+
import { path as packageJsonPath } from "../widget/package";
99

1010
const pluggableWidgetsTools = "@mendix/pluggable-widgets-tools" as NpmAudit.PackageName;
1111

@@ -58,7 +58,6 @@ export async function auditPluggableWidgetsTools(fix: boolean = false) {
5858
(fix || (await confirm("Add overrides to package.json for vulnerable packages?")))
5959
) {
6060
console.log("Adding overrides");
61-
const packageJsonPath = join(process.cwd(), "package.json");
6261
const widgetPackage = await promisify(readFile)(packageJsonPath, "utf8").then(raw => JSON.parse(raw));
6362

6463
const overrides = updateable

packages/pluggable-widgets-tools/src/utils/enzyme-detector.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
22
import { join } from "path";
33
import { yellow } from "ansi-colors";
4+
import { widgetRoot } from "../widget/paths";
45

56
export function checkForEnzymeUsage(srcDir: string = "src"): void {
6-
const projectRoot = process.cwd();
7-
const srcPath = join(projectRoot, srcDir);
7+
const srcPath = join(widgetRoot, srcDir);
88

99
if (!existsSync(srcPath)) {
1010
return;
@@ -36,7 +36,7 @@ export function checkForEnzymeUsage(srcDir: string = "src"): void {
3636
content
3737
)
3838
) {
39-
enzymeFiles.push(fullPath.replace(projectRoot, "."));
39+
enzymeFiles.push(fullPath.replace(widgetRoot, "."));
4040
}
4141
}
4242
} catch (error) {

packages/pluggable-widgets-tools/src/utils/formatting.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
import { readFile } from "fs/promises";
1+
import { existsSync } from "fs";
22
import { join } from "path";
3-
import { resolveConfig, format, Options } from "prettier";
4-
import { cwd } from "process";
3+
import { format, Options } from "prettier";
4+
import { toolsRoot, widgetRoot } from "../widget/paths";
55

6-
const prettierConfigBasePath = join(__dirname, "../../configs/prettier.base.json");
6+
const baseConfigPath = join(toolsRoot, "./configs/prettier.base.json");
7+
const widgetConfigPath = join(widgetRoot, "./prettier.config.js");
8+
export const prettierConfigPath = existsSync(widgetConfigPath) ? widgetConfigPath : baseConfigPath;
79

810
let prettierTypescriptConfig: Options | undefined;
911

@@ -13,11 +15,7 @@ let prettierTypescriptConfig: Options | undefined;
1315
*/
1416
export async function formatTypeScript(source: string): Promise<string> {
1517
if (prettierTypescriptConfig === undefined) {
16-
const fakeFilename = join(cwd(), "./src/widget.ts");
17-
// If the widget does not have a prettier config, fall back to packaged base config
18-
const prettierConfig =
19-
(await resolveConfig(fakeFilename)) ?? JSON.parse(await readFile(prettierConfigBasePath, "utf-8"));
20-
18+
const prettierConfig = await import(prettierConfigPath);
2119
prettierTypescriptConfig = {
2220
...prettierConfig,
2321
parser: "babel-ts"

packages/pluggable-widgets-tools/src/utils/npmAudit.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import assert from "node:assert";
22
import { exec } from "node:child_process";
33
import { existsSync } from "node:fs";
44
import { join } from "node:path";
5+
import { widgetRoot } from "../widget/paths";
56

67
export type Report = {
78
auditReportVersion: 2;
@@ -70,7 +71,7 @@ export function collectVulnerabilities(report: Report, dependency: Dependency):
7071
}
7172

7273
export async function run(): Promise<Report> {
73-
const packageLock = join(process.cwd(), "package-lock.json");
74+
const packageLock = join(widgetRoot, "package-lock.json");
7475
assert(
7576
existsSync(packageLock),
7677
"Expected to find an npm lockfile. To run npm audit, dependencies must be installed with npm."
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { existsSync, readFileSync } from "fs";
2+
import { throwOnIllegalChars, throwOnNoMatch } from "../utils/validation";
3+
import { join } from "path";
4+
import { cwd } from "process";
5+
6+
/**
7+
* The full path to the root directory of the widget package
8+
*/
9+
export const dir = cwd();
10+
11+
/**
12+
* The full path to the widget's package.json file
13+
*/
14+
export const path = join(dir, "package.json");
15+
if (!existsSync(path)) {
16+
throw new Error(`"Could not locate the widget's package.json at "${path}"`);
17+
}
18+
19+
/**
20+
* The contents of the widget's package.json
21+
*/
22+
export const json = JSON.parse(readFileSync(path, "utf-8"));
23+
24+
/**
25+
* The name of the widget
26+
*/
27+
export const widgetName: string = json.widgetName;
28+
if (!widgetName) {
29+
throw new Error("Widget does not define widgetName in its package.json");
30+
}
31+
throwOnIllegalChars(widgetName, "a-zA-Z", "The `widgetName` property in package.json");
32+
33+
/**
34+
* The organization name of the widget as defined by the `packagePath` package.json property.
35+
*/
36+
export const widgetOrganization: string = json.packagePath;
37+
throwOnIllegalChars(widgetOrganization, "a-zA-Z0-9_.-", "The `packagePath` property in package.json");
38+
throwOnNoMatch(widgetOrganization, /^([a-zA-Z0-9_-]+.)*[a-zA-Z0-9_-]+$/, "The `packagePath` property in package.json");
39+
40+
/**
41+
* The name of the widget package
42+
*/
43+
export const packageName: string = json.name;
44+
45+
/**
46+
* The version of the widget package.
47+
*/
48+
export const widgetVersion: string = json.version;
49+
50+
/**
51+
* The ID of the widget
52+
*/
53+
export const widgetId: string = [widgetOrganization, packageName, widgetName].join(".");
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { join } from "path";
2+
3+
export { dir as widgetRoot } from "./package";
4+
5+
/**
6+
* The full path to the root of the pluggable-widgets-tools
7+
*/
8+
export const toolsRoot = join(__dirname, "../..");

0 commit comments

Comments
 (0)