@p8ec/shared 3.0.0 → 3.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -69,3 +69,5 @@ p8-cli [command] [options]
69
69
  - Example: `p8-cli run build` - returns the `build` script using the detected package manager.
70
70
  - Example: `p8-cli run test auto par` - returns the `test` script using the detected
71
71
  package manager in parallel mode for workspaces.
72
+ - `pm` - Returns the detected package manager (`npm`, `yarn`, or `pnpm`).
73
+ - `ws` - Returns `true` if the project is a workspace, `false` otherwise.
@@ -7,10 +7,34 @@ pre-commit:
7
7
  commands:
8
8
  git:
9
9
  run: |
10
- if [[ $(git rev-parse --abbrev-ref HEAD) =~ ^(main|master|release)$ ]]; then
11
- echo "Direct commits to main, master, and release branches are not allowed."
12
- exit 1
10
+ if [[ $(git rev-parse --abbrev-ref HEAD) =~ ^(main|master|release)$ ]]; then
11
+ # Allow direct commits on protected branches ONLY if the staged changes are package.json
12
+ STAGED_FILES=$(git diff --cached --name-only)
13
+
14
+ if [[ -z "$STAGED_FILES" ]]; then
15
+ exit 0
13
16
  fi
17
+
18
+ ALLOWED_FILES=${ALLOWED_FILES:-"package.json"}
19
+ IFS=',' read -r -a ALLOWED_ARRAY <<< "$ALLOWED_FILES"
20
+
21
+ # Check every staged file; if any differs from the allowed files, block the commit
22
+ for f in $STAGED_FILES; do
23
+ MATCHED=false
24
+ for allowed in "${ALLOWED_ARRAY[@]}"; do
25
+ if [[ "$f" == "$allowed" || "$f" == */"$allowed" ]]; then
26
+ MATCHED=true
27
+ break
28
+ fi
29
+ done
30
+
31
+ if [[ "$MATCHED" == "false" ]]; then
32
+ echo "Direct commits to main, master, and release branches are not allowed, except for: $ALLOWED_FILES"
33
+ exit 1
34
+ fi
35
+ done
36
+ fi
37
+
14
38
 
15
39
  ### Commit message hook ###
16
40
  # 1. Allow only commit messages that follow a conventional commit format
@@ -75,28 +75,38 @@ exports.initCleanup = initCleanup;
75
75
  /**
76
76
  * Initializes a TypeScript project with P8 shared configurations.
77
77
  */
78
- const init = (option_1, ...args_1) => __awaiter(void 0, [option_1, ...args_1], void 0, function* (option, packageManager = (0, detect_1.detectPackageManager)()) {
79
- var _a;
78
+ const init = (option_1, ...args_1) => __awaiter(void 0, [option_1, ...args_1], void 0, function* (option, pm = 'auto') {
80
79
  const packageJsonData = fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf8');
81
80
  const packageJson = JSON.parse(packageJsonData);
82
81
  const moduleType = packageJson['type'] === 'module' ? 'mjs' : 'cjs';
82
+ const packageManager = pm === 'auto' ? (0, detect_1.detectPackageManager)() : pm;
83
83
  writeLn(`Creating eslint.config.${moduleType}...`);
84
84
  p8_shared_cli_1.cliUtils.copyAsset(`eslint.config.${moduleType}`);
85
85
  writeLn(`Creating prettier.config.${moduleType}...`);
86
86
  p8_shared_cli_1.cliUtils.copyAsset(`prettier.config.${moduleType}`);
87
- (_a = packageJson.scripts) !== null && _a !== void 0 ? _a : (packageJson.scripts = {});
88
- packageJson.scripts[`${packageManager}:reset`] =
89
- packageManager === 'pnpm'
90
- ? 'rm -rf ./**/node_modules && rm -rf ./**/pnpm-lock.yaml && pnpm install'
91
- : packageManager === 'yarn'
92
- ? 'rm -rf ./**/node_modules && rm -rf ./**/yarn.lock && yarn install'
93
- : 'rm -rf ./**/node_modules && rm -rf ./**/package-lock.json && npm install';
94
- packageJson.scripts[`${packageManager}:audit`] =
95
- packageManager === 'pnpm'
96
- ? 'pnpm audit'
97
- : packageManager === 'yarn'
98
- ? 'yarn npm audit'
99
- : 'npm audit --audit-level=moderate';
87
+ const scripts = [
88
+ {
89
+ name: 'reset',
90
+ command: {
91
+ pnpm: 'rm -rf ./**/node_modules && rm -rf ./**/pnpm-lock.yaml && pnpm install',
92
+ yarn: 'rm -rf ./**/node_modules && rm -rf ./**/yarn.lock && yarn install',
93
+ npm: 'rm -rf ./**/node_modules && rm -rf ./**/package-lock.json && npm install',
94
+ },
95
+ },
96
+ {
97
+ name: 'audit',
98
+ command: {
99
+ pnpm: 'pnpm audit',
100
+ yarn: 'yarn npm audit',
101
+ npm: 'npm audit --audit-level=moderate',
102
+ },
103
+ },
104
+ ];
105
+ scripts.forEach((script) => {
106
+ var _a;
107
+ (_a = packageJson.scripts) !== null && _a !== void 0 ? _a : (packageJson.scripts = {});
108
+ packageJson.scripts[`${packageManager}:${script.name}`] = script.command[packageManager];
109
+ });
100
110
  const lefthook = yield (0, yesno_1.default)({
101
111
  question: 'Do you want to use commitlint/lefthook? [y]n',
102
112
  defaultValue: true,
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ /**
3
+ * 2026 Copyright P8 Enterprise Components, Inc.
4
+ * All Rights Reserved.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.root = void 0;
8
+ const detect_1 = require("../utils/detect");
9
+ /**
10
+ * Returns the root directory of the project.
11
+ */
12
+ const root = (cwd = process.cwd()) => {
13
+ return (0, detect_1.detectRoot)(cwd);
14
+ };
15
+ exports.root = root;
@@ -50,7 +50,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
50
50
  return (mod && mod.__esModule) ? mod : { "default": mod };
51
51
  };
52
52
  Object.defineProperty(exports, "__esModule", { value: true });
53
- exports.cliUtils = exports.IS_DEV = exports.detectWorkspace = exports.detectPackageManager = exports.run = exports.dirn = exports.initCleanup = exports.init = void 0;
53
+ exports.main = exports.cliUtils = exports.IS_DEV = exports.detectWorkspace = exports.detectPackageManager = exports.root = exports.run = exports.dirn = exports.initCleanup = exports.init = void 0;
54
54
  /**
55
55
  * P8 Shared CLI tool.
56
56
  *
@@ -70,20 +70,27 @@ const dirn_1 = require("./cmds/dirn");
70
70
  Object.defineProperty(exports, "dirn", { enumerable: true, get: function () { return dirn_1.dirn; } });
71
71
  const run_1 = require("./cmds/run");
72
72
  Object.defineProperty(exports, "run", { enumerable: true, get: function () { return run_1.run; } });
73
+ const root_1 = require("./cmds/root");
74
+ Object.defineProperty(exports, "root", { enumerable: true, get: function () { return root_1.root; } });
73
75
  const detect_1 = require("./utils/detect");
74
76
  Object.defineProperty(exports, "detectPackageManager", { enumerable: true, get: function () { return detect_1.detectPackageManager; } });
75
77
  Object.defineProperty(exports, "detectWorkspace", { enumerable: true, get: function () { return detect_1.detectWorkspace; } });
76
78
  exports.IS_DEV = process.env.NODE_ENV === 'development';
77
79
  let args = ferramenta_1.processArgs.args;
78
80
  const self = path.parse(ferramenta_1.processArgs.name).name;
79
- const writeLn = console.log;
81
+ const writeLn = (...args) => {
82
+ console.log(...args);
83
+ };
80
84
  exports.cliUtils = {
81
- execShell: (command) => exports.IS_DEV ? writeLn(`DEV: execShell ${command}`) : child_process.execSync(command).toString(),
85
+ writeLn: (...args) => {
86
+ writeLn(...args);
87
+ },
88
+ execShell: (command) => exports.IS_DEV ? exports.cliUtils.writeLn(`DEV: execShell ${command}`) : child_process.execSync(command).toString(),
82
89
  writeFile: (name, data) => exports.IS_DEV
83
- ? writeLn(`DEV: writeFile name=${name} data=${data}`)
90
+ ? console.log(`DEV: writeFile name=${name} data=${data}`)
84
91
  : fs.writeFileSync(path.join(process.cwd(), name), data),
85
92
  copyAsset: (name) => exports.IS_DEV
86
- ? writeLn(`DEV: copyAsset name=${name}`)
93
+ ? console.log(`DEV: copyAsset name=${name}`)
87
94
  : fs.copyFileSync(path.join(__dirname, '..', '..', 'assets', name), path.join(process.cwd(), name)),
88
95
  };
89
96
  if (args.length === 0 && !exports.IS_DEV && require.main === module) {
@@ -104,37 +111,56 @@ Commands:
104
111
  Arguments:
105
112
  script: The script to run.
106
113
  Options:
107
- -p {value}, --packageManager={value}: The package manager to use, where {value} is one of 'npm', 'pnpm', 'yarn', or 'auto'.
108
- -w {value}, --workspaceMode={value}: The workspace mode to use, where {value} is one of 'none', 'seq', 'par', or 'auto'.
114
+ -p {value}, --packageManager={value}: The package manager to use, where {value} is one of 'npm', 'pnpm', 'yarn', or 'auto' (defaults to 'auto').
115
+ -w {value}, --workspaceMode={value}: The workspace mode to use, where {value} is one of 'none', 'seq', 'par', or 'auto' (defaults to 'auto').
116
+ root
117
+ Returns path to the root of the repo.
118
+ pm
119
+ Returns the detected package manager.
120
+ ws
121
+ Returns true or false for detected workspace.
109
122
  `);
110
123
  if (exports.IS_DEV) {
111
124
  writeLn(`DEVELOPMENT MODE`);
112
125
  }
113
126
  process.exit(1);
114
127
  }
115
- const main = () => __awaiter(void 0, void 0, void 0, function* () {
128
+ const main = (customArgs) => __awaiter(void 0, void 0, void 0, function* () {
116
129
  // Ask the user for arguments if IS_DEV is true
117
- if (exports.IS_DEV) {
130
+ if (exports.IS_DEV && !customArgs) {
118
131
  args = (yield (0, prompt_1.default)('Enter arguments:')).split(' ');
119
132
  }
133
+ else if (customArgs) {
134
+ args = customArgs;
135
+ }
120
136
  const parsed = (0, args_1.default)(args);
121
137
  switch (parsed.command) {
122
138
  case 'init':
123
139
  yield (0, init_1.init)(parsed.positional[0] || (parsed.options.cleanup ? 'cleanup' : ''));
124
140
  break;
125
141
  case 'dirn':
126
- writeLn((0, dirn_1.dirn)(parsed.positional[0]));
142
+ exports.cliUtils.writeLn((0, dirn_1.dirn)(parsed.positional[0]));
127
143
  break;
128
144
  case 'run':
129
- writeLn((0, run_1.run)(parsed.positional[0], (parsed.positional[1] || parsed.options.p || parsed.options.packageManager), (parsed.positional[2] || parsed.options.w || parsed.options.workspaceMode)));
145
+ exports.cliUtils.writeLn((0, run_1.run)(parsed.positional[0], (parsed.positional[1] || parsed.options.p || parsed.options.packageManager), (parsed.positional[2] || parsed.options.w || parsed.options.workspaceMode)));
146
+ break;
147
+ case 'root':
148
+ exports.cliUtils.writeLn((0, root_1.root)());
149
+ break;
150
+ case 'pm':
151
+ exports.cliUtils.writeLn((0, detect_1.detectPackageManager)());
152
+ break;
153
+ case 'ws':
154
+ exports.cliUtils.writeLn((0, detect_1.detectWorkspace)());
130
155
  break;
131
156
  default:
132
157
  console.error(`Unknown command: ${parsed.command}`);
133
158
  process.exit(1);
134
159
  }
135
160
  });
161
+ exports.main = main;
136
162
  if (require.main === module) {
137
- main()
163
+ (0, exports.main)()
138
164
  .then((r) => {
139
165
  if (exports.IS_DEV) {
140
166
  writeLn(`DEV: setup completed successfully with result: ${JSON.stringify(r)}`);
@@ -37,17 +37,53 @@ var __importStar = (this && this.__importStar) || (function () {
37
37
  };
38
38
  })();
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.detectWorkspace = exports.detectPackageManager = void 0;
40
+ exports.detectWorkspace = exports.detectPackageManager = exports.detectRoot = void 0;
41
41
  const fs = __importStar(require("node:fs"));
42
42
  const path = __importStar(require("node:path"));
43
+ /**
44
+ * Finds the TOPMOST directory containing package.json
45
+ * by walking up the directory tree.
46
+ * @param startDir Directory to start from (defaults to cwd)
47
+ * @returns Absolute path to monorepo root, or null if none found
48
+ */
49
+ const detectRoot = (startDir = process.cwd()) => {
50
+ let currentDir = path.resolve(startDir);
51
+ // Avoid symlink loops
52
+ try {
53
+ currentDir = fs.realpathSync(currentDir);
54
+ }
55
+ catch (_a) {
56
+ // ignore
57
+ }
58
+ let lastMatch = startDir;
59
+ while (true) {
60
+ const pkgPath = path.join(currentDir, 'package.json');
61
+ try {
62
+ if (fs.existsSync(pkgPath)) {
63
+ lastMatch = currentDir;
64
+ }
65
+ }
66
+ catch (_b) {
67
+ // ignore fs errors and continue walking up
68
+ }
69
+ const parentDir = path.dirname(currentDir);
70
+ if (parentDir === currentDir) {
71
+ break; // filesystem root reached
72
+ }
73
+ currentDir = parentDir;
74
+ }
75
+ return lastMatch;
76
+ };
77
+ exports.detectRoot = detectRoot;
43
78
  /**
44
79
  * Detects the package manager used in the project.
45
80
  */
46
81
  const detectPackageManager = (cwd = process.cwd()) => {
47
- if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {
82
+ const root = (0, exports.detectRoot)(cwd);
83
+ if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) {
48
84
  return 'pnpm';
49
85
  }
50
- if (fs.existsSync(path.join(cwd, 'yarn.lock'))) {
86
+ if (fs.existsSync(path.join(root, 'yarn.lock'))) {
51
87
  return 'yarn';
52
88
  }
53
89
  return 'npm';
@@ -57,10 +93,11 @@ exports.detectPackageManager = detectPackageManager;
57
93
  * Detects if the project is a workspace.
58
94
  */
59
95
  const detectWorkspace = (cwd = process.cwd()) => {
60
- if (fs.existsSync(path.join(cwd, 'pnpm-workspace.yaml'))) {
96
+ const root = (0, exports.detectRoot)(cwd);
97
+ if (fs.existsSync(path.join(root, 'pnpm-workspace.yaml'))) {
61
98
  return true;
62
99
  }
63
- const packageJsonPath = path.join(cwd, 'package.json');
100
+ const packageJsonPath = path.join(root, 'package.json');
64
101
  if (fs.existsSync(packageJsonPath)) {
65
102
  try {
66
103
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@p8ec/shared",
3
- "version": "3.0.0",
3
+ "version": "3.0.3",
4
4
  "description": "P(8) Global Shared Library for Javascript",
5
5
  "repository": {
6
6
  "type": "git",