@funish/basis 0.0.1 → 0.0.2

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 (56) hide show
  1. package/README.md +70 -24
  2. package/dist/chunks/config.cjs +1 -1
  3. package/dist/chunks/config.mjs +1 -1
  4. package/dist/chunks/git.cjs +1 -0
  5. package/dist/chunks/git.mjs +1 -0
  6. package/dist/chunks/init.cjs +1 -1
  7. package/dist/chunks/init.mjs +1 -1
  8. package/dist/chunks/lint.cjs +1 -1
  9. package/dist/chunks/lint.mjs +1 -1
  10. package/dist/chunks/publish.cjs +1 -1
  11. package/dist/chunks/publish.mjs +1 -1
  12. package/dist/chunks/version.cjs +1 -1
  13. package/dist/chunks/version.mjs +1 -1
  14. package/dist/cli.cjs +1 -1
  15. package/dist/cli.mjs +1 -1
  16. package/dist/config.cjs +1 -1
  17. package/dist/config.d.cts +1 -1
  18. package/dist/config.d.mts +1 -1
  19. package/dist/config.d.ts +1 -1
  20. package/dist/config.mjs +1 -1
  21. package/dist/index.cjs +1 -1
  22. package/dist/index.d.cts +193 -24
  23. package/dist/index.d.mts +193 -24
  24. package/dist/index.d.ts +193 -24
  25. package/dist/index.mjs +1 -1
  26. package/dist/shared/{basis.dc3ybBoz.mjs → basis.BglwV-us.mjs} +1 -1
  27. package/dist/shared/{basis.CgpyxNW3.cjs → basis.Bhi6kSAJ.cjs} +1 -1
  28. package/dist/shared/basis.BjS41bTE.cjs +1 -0
  29. package/dist/shared/basis.BvLeB_5F.d.cts +253 -0
  30. package/dist/shared/basis.BvLeB_5F.d.mts +253 -0
  31. package/dist/shared/basis.BvLeB_5F.d.ts +253 -0
  32. package/dist/shared/basis.C7U9rUSl.mjs +1 -0
  33. package/dist/shared/basis.CASkqgVR.mjs +1 -0
  34. package/dist/shared/basis.D2srGCU3.cjs +1 -0
  35. package/dist/shared/basis.D3bv4yUV.mjs +3 -0
  36. package/dist/shared/basis.DHqql56x.mjs +10 -0
  37. package/dist/shared/basis.DXBdQ4nF.mjs +1 -0
  38. package/dist/shared/basis.DcyVtmjR.cjs +1 -0
  39. package/dist/shared/basis.FJWRn1Ix.cjs +3 -0
  40. package/dist/shared/basis.QoGvLLsN.cjs +10 -0
  41. package/package.json +5 -3
  42. package/dist/chunks/githooks.cjs +0 -1
  43. package/dist/chunks/githooks.mjs +0 -1
  44. package/dist/shared/basis.ByJ8R9TE.cjs +0 -1
  45. package/dist/shared/basis.C0E7mwQ6.mjs +0 -1
  46. package/dist/shared/basis.C5wlo6IO.mjs +0 -1
  47. package/dist/shared/basis.CBZIV3-V.mjs +0 -19
  48. package/dist/shared/basis.CSSuyvpq.cjs +0 -1
  49. package/dist/shared/basis.D57HxVvD.cjs +0 -4
  50. package/dist/shared/basis.DeKfEQsQ.cjs +0 -5
  51. package/dist/shared/basis.DweCjqFb.cjs +0 -19
  52. package/dist/shared/basis.O4so-uuj.mjs +0 -5
  53. package/dist/shared/basis.iRZ1Ylu8.d.cts +0 -127
  54. package/dist/shared/basis.iRZ1Ylu8.d.mts +0 -127
  55. package/dist/shared/basis.iRZ1Ylu8.d.ts +0 -127
  56. package/dist/shared/basis.rDVxD7qf.mjs +0 -4
@@ -0,0 +1,253 @@
1
+ interface BasisConfig {
2
+ lint?: LintConfig;
3
+ git?: GitConfig;
4
+ packageManager?: PackageManagerConfig;
5
+ version?: VersionConfig;
6
+ publish?: PublishConfig;
7
+ }
8
+ interface LintConfig {
9
+ staged?: Record<string, string>;
10
+ project?: Record<string, string>;
11
+ dependencies?: {
12
+ checkOutdated?: boolean;
13
+ checkSecurity?: boolean;
14
+ allowedLicenses?: string[];
15
+ blockedPackages?: string[];
16
+ };
17
+ structure?: {
18
+ requiredFiles?: string[];
19
+ requiredDirs?: string[];
20
+ naming?: Array<{
21
+ path: string;
22
+ files?: string;
23
+ directories?: string;
24
+ description?: string;
25
+ }>;
26
+ };
27
+ docs?: {
28
+ checkReadme?: boolean;
29
+ checkChangelog?: boolean;
30
+ };
31
+ }
32
+ interface GitConfig {
33
+ hooks?: Partial<Record<ValidGitHook, string>>;
34
+ config?: {
35
+ core?: {
36
+ editor?: string;
37
+ autocrlf?: boolean | "input";
38
+ eol?: "lf" | "crlf" | "native";
39
+ ignorecase?: boolean;
40
+ filemode?: boolean;
41
+ bare?: boolean;
42
+ logallrefupdates?: boolean;
43
+ repositoryformatversion?: number;
44
+ sharedrepository?: boolean | "group" | "all" | "world" | "everybody";
45
+ worktree?: string;
46
+ precomposeunicode?: boolean;
47
+ protecthfs?: boolean;
48
+ protectntfs?: boolean;
49
+ };
50
+ user?: {
51
+ name?: string;
52
+ email?: string;
53
+ signingkey?: string;
54
+ };
55
+ init?: {
56
+ defaultBranch?: string;
57
+ };
58
+ branch?: {
59
+ autosetupmerge?: boolean | "always";
60
+ autosetuprebase?: "never" | "local" | "remote" | "always";
61
+ };
62
+ push?: {
63
+ default?: "nothing" | "current" | "upstream" | "simple" | "matching";
64
+ followTags?: boolean;
65
+ autoSetupRemote?: boolean;
66
+ };
67
+ pull?: {
68
+ rebase?: boolean | "preserve" | "merges" | "interactive";
69
+ ff?: boolean | "only";
70
+ };
71
+ merge?: {
72
+ tool?: string;
73
+ conflictstyle?: "merge" | "diff3";
74
+ ff?: boolean | "only";
75
+ log?: boolean | number;
76
+ };
77
+ rebase?: {
78
+ autoSquash?: boolean;
79
+ autoStash?: boolean;
80
+ updateRefs?: boolean;
81
+ };
82
+ fetch?: {
83
+ prune?: boolean;
84
+ pruneTags?: boolean;
85
+ fsckobjects?: boolean;
86
+ };
87
+ remote?: {
88
+ [remoteName: string]: {
89
+ url?: string;
90
+ fetch?: string;
91
+ };
92
+ };
93
+ diff?: {
94
+ tool?: string;
95
+ algorithm?: "myers" | "minimal" | "patience" | "histogram";
96
+ renames?: boolean | "copy" | "copies";
97
+ mnemonicprefix?: boolean;
98
+ };
99
+ status?: {
100
+ showUntrackedFiles?: "no" | "normal" | "all";
101
+ branch?: boolean;
102
+ short?: boolean;
103
+ };
104
+ commit?: {
105
+ cleanup?: "strip" | "whitespace" | "verbatim" | "scissors" | "default";
106
+ gpgsign?: boolean;
107
+ template?: string;
108
+ verbose?: boolean;
109
+ };
110
+ log?: {
111
+ abbrevCommit?: boolean;
112
+ decorate?: boolean | "short" | "full" | "auto" | "no";
113
+ showSignature?: boolean;
114
+ };
115
+ transfer?: {
116
+ fsckobjects?: boolean;
117
+ };
118
+ receive?: {
119
+ fsckObjects?: boolean;
120
+ };
121
+ gc?: {
122
+ auto?: number;
123
+ autopacklimit?: number;
124
+ autodetach?: boolean;
125
+ };
126
+ alias?: {
127
+ [aliasName: string]: string;
128
+ };
129
+ url?: {
130
+ [pattern: string]: {
131
+ insteadOf?: string;
132
+ pushInsteadOf?: string;
133
+ };
134
+ };
135
+ };
136
+ commitMsg?: CommitMsgConfig;
137
+ autoSetup?: boolean;
138
+ autoInitGit?: boolean;
139
+ skipGitCheck?: boolean;
140
+ force?: boolean;
141
+ }
142
+ interface CommitMsgConfig {
143
+ types?: string[];
144
+ maxLength?: number;
145
+ minLength?: number;
146
+ scopeRequired?: boolean;
147
+ allowedScopes?: string[];
148
+ }
149
+ interface CommitMessage {
150
+ type: string;
151
+ scope?: string;
152
+ description: string;
153
+ body?: string;
154
+ footer?: string;
155
+ isBreaking: boolean;
156
+ }
157
+ declare const VALID_GIT_HOOKS: readonly ["applypatch-msg", "pre-applypatch", "post-applypatch", "pre-commit", "pre-merge-commit", "prepare-commit-msg", "commit-msg", "post-commit", "pre-rebase", "post-checkout", "post-merge", "pre-push", "pre-receive", "update", "proc-receive", "post-receive", "post-update", "reference-transaction", "push-to-checkout", "pre-auto-gc", "post-rewrite", "sendemail-validate", "fsmonitor-watchman", "p4-changelist", "p4-prepare-changelist", "p4-post-changelist", "p4-pre-submit", "post-index-change"];
158
+ type ValidGitHook = (typeof VALID_GIT_HOOKS)[number];
159
+ type GitConfigValue = string | number | boolean;
160
+ type GitConfigSection = Record<string, GitConfigValue>;
161
+ type GitConfigData = Record<string, GitConfigSection>;
162
+ interface PackageManagerConfig {
163
+ /** Preferred package manager (aligned with nypm support) */
164
+ preferred?: "npm" | "yarn" | "pnpm" | "bun" | "deno";
165
+ /** Auto-detect package manager from project */
166
+ autoDetect?: boolean;
167
+ /** NPM registry URL */
168
+ registry?: string;
169
+ }
170
+ interface VersionConfig {
171
+ /** Git tag prefix */
172
+ tagPrefix?: string;
173
+ /** Auto commit version changes */
174
+ autoCommit?: boolean;
175
+ /** Auto create git tag */
176
+ autoTag?: boolean;
177
+ /** Auto push changes to remote */
178
+ autoPush?: boolean;
179
+ /** Prerelease identifier (alpha, beta, rc) */
180
+ prereleaseId?: string;
181
+ /** Commit message template */
182
+ commitMessage?: string;
183
+ }
184
+ interface PublishConfig {
185
+ /** NPM registry URL */
186
+ registry?: string;
187
+ /** Package access level */
188
+ access?: "public" | "private";
189
+ /** Default publish tag (for non-stable releases) */
190
+ defaultTag?: string;
191
+ /** Stable release tag */
192
+ stableTag?: string;
193
+ /** Build command before publish */
194
+ buildCommand?: string;
195
+ /** Test command before publish */
196
+ testCommand?: string;
197
+ /** Check git working directory is clean */
198
+ checkGitClean?: boolean;
199
+ /** Run tests before publish */
200
+ checkTests?: boolean;
201
+ /** Auto push git changes after publish */
202
+ autoGitPush?: boolean;
203
+ /** Create git tag after publish */
204
+ createGitTag?: boolean;
205
+ }
206
+ interface InitOptions {
207
+ force?: boolean;
208
+ skipGitCheck?: boolean;
209
+ skipInstall?: boolean;
210
+ }
211
+ interface VersionOptions {
212
+ version?: string;
213
+ preid?: string;
214
+ prerelease?: boolean;
215
+ major?: boolean;
216
+ minor?: boolean;
217
+ patch?: boolean;
218
+ tag?: string;
219
+ message?: string;
220
+ }
221
+ interface PublishOptions {
222
+ tag?: string;
223
+ stable?: boolean;
224
+ latest?: boolean;
225
+ dryRun?: boolean;
226
+ access?: "public" | "private";
227
+ registry?: string;
228
+ skipBuild?: boolean;
229
+ skipTests?: boolean;
230
+ }
231
+ interface VersionUpdateResult {
232
+ oldVersion: string;
233
+ newVersion: string;
234
+ tagName?: string;
235
+ }
236
+ interface PublishResult {
237
+ packageName: string;
238
+ version: string;
239
+ publishTag: string;
240
+ dryRun: boolean;
241
+ }
242
+
243
+ /**
244
+ * Define a Basis configuration
245
+ */
246
+ declare function defineBasisConfig(config: BasisConfig): BasisConfig;
247
+ /**
248
+ * Default configuration
249
+ */
250
+ declare const defaultConfig: BasisConfig;
251
+
252
+ export { defineBasisConfig as d, defaultConfig as e, VALID_GIT_HOOKS as g };
253
+ export type { BasisConfig as B, CommitMessage as C, GitConfig as G, InitOptions as I, LintConfig as L, PublishOptions as P, VersionOptions as V, VersionUpdateResult as a, PublishResult as b, GitConfigData as c, CommitMsgConfig as f, ValidGitHook as h, GitConfigValue as i, GitConfigSection as j, PackageManagerConfig as k, VersionConfig as l, PublishConfig as m };
@@ -0,0 +1 @@
1
+ import{access as t}from"node:fs/promises";import{loadConfig as o}from"c12";import{defaultConfig as s}from"../config.mjs";async function f(a={}){return await o({name:"basis",cwd:process.cwd(),...a,defaults:{...s,...a.defaults}})}async function r(a){try{return await t(a),!0}catch{return!1}}export{r as f,f as l};
@@ -0,0 +1 @@
1
+ import{execSync as g}from"node:child_process";import{consola as s}from"consola";import{readPackageJSON as v,resolvePackageJSON as f,writePackageJSON as h}from"pkg-types";import m from"semver";import{l as $}from"./basis.C7U9rUSl.mjs";async function P(r,o={}){const{config:u}=await $({cwd:r}),i=u.version||{},d=await v(r),t=d.version;if(!t)throw new Error("No version found in package.json");const n=o.version?m.valid(o.version)?o.version:(()=>{throw new Error(`Invalid version format: ${o.version}`)})():(()=>{if(!m.valid(t))throw new Error(`Invalid current version format: ${t}`);const e=m.prerelease(t),c=o.preid||(e&&typeof e[0]=="string"?e[0]:null)||i.prereleaseId||"edge";let a;o.major?a="major":o.minor?a="minor":o.prerelease?a=e?"prerelease":"prepatch":a=e?"prerelease":"patch";const l=a==="prerelease"||a.startsWith("pre")?m.inc(t,a,c):m.inc(t,a);if(!l)throw new Error("Failed to calculate new version");return l})();s.info(`Updating version: ${t} \u2192 ${n}`);const w=await f(r);await h(w,{...d,version:n});const p={oldVersion:t,newVersion:n};if(i.autoCommit){const e=o.message||i.commitMessage?.replace("{version}",n)||`chore: release v${n}`;try{g("git add package.json",{cwd:r}),g(`git commit -m "${e}"`,{cwd:r}),s.success(`Committed version update: ${e}`)}catch(c){s.warn("Failed to commit changes:",c)}}if(i.autoTag){const e=`${i.tagPrefix||"v"}${n}`;try{g(`git tag ${e}`,{cwd:r}),s.success(`Created git tag: ${e}`),p.tagName=e}catch(c){s.warn("Failed to create git tag:",c)}}if(i.autoPush)try{g("git push",{cwd:r}),i.autoTag&&g("git push --tags",{cwd:r}),s.success("Pushed changes to remote")}catch(e){s.warn("Failed to push changes:",e)}return p}export{P as u};
@@ -0,0 +1 @@
1
+ "use strict";const promises=require("node:fs/promises"),consola=require("consola"),magicast=require("magicast"),nypm=require("nypm"),pathe=require("pathe"),pkgTypes=require("pkg-types"),utils=require("./basis.DcyVtmjR.cjs");function v(){const e=magicast.parseModule("export default {}"),i=magicast.builders.functionCall("defineBasisConfig",[{}]),n={staged:{},project:{}},c={hooks:{}},o=i.$args[0];o.lint=n,o.git=c,e.exports.default=i,e.imports.$prepend({from:"@funish/basis",imported:"defineBasisConfig"});const{code:a}=magicast.generateCode(e);return a}function C(e){const{enableStagedLinting:i=!1,enableCommitMsgLinting:n=!1,customLintPatterns:c,customExcludePatterns:o}=e,a=magicast.parseModule("export default defineBasisConfig({})"),t=a.exports.default.$args[0];t.lint={},t.lint.staged={},i&&(t.lint.staged["*.{js,ts,jsx,tsx}"]="eslint --fix",t.lint.staged["*.{css,scss,less}"]="stylelint --fix"),t.lint.project={patterns:c||["src/**/*","lib/**/*","*.{js,ts,jsx,tsx}"],exclude:o||["node_modules/**","dist/**","build/**"]},t.git={},t.git.hooks={},i&&(t.git.hooks["pre-commit"]="basis lint --staged"),n&&(t.git.hooks["commit-msg"]="basis git --lint-commit"),t.git.commitMsg={},a.imports.$items.some(s=>s.from==="@funish/basis")||a.imports.$prepend({from:"@funish/basis",imported:"defineBasisConfig"});const{code:l}=magicast.generateCode(a);return l}async function D(){const e=await consola.consola.prompt("Enable staged files linting?",{type:"confirm",initial:!0}),i=await consola.consola.prompt("Enable commit message linting?",{type:"confirm",initial:!0});let n;if(await consola.consola.prompt("Customize lint file patterns?",{type:"confirm",initial:!1})){const c=await consola.consola.prompt("Enter lint patterns (comma-separated):",{type:"text",initial:"src/**/*,lib/**/*,*.{js,ts,jsx,tsx}"});typeof c=="string"&&(n=c.split(",").map(o=>o.trim()))}return{enableStagedLinting:e,enableCommitMsgLinting:i,customLintPatterns:n}}async function init(e=process.cwd(),i={}){const{force:n=!1,skipGitCheck:c=!1,skipInstall:o=!1}=i;consola.consola.start("Initializing basis configuration...");const a=pathe.resolve(e,"basis.config.ts");if(await utils.fileExists(a)&&!n)return consola.consola.error("basis.config.ts already exists. Use --force to overwrite."),!1;if(!c&&!await utils.fileExists(pathe.resolve(e,".git"))&&(consola.consola.warn("No .git directory found. Git hooks will not work properly."),!await consola.consola.prompt("Continue anyway?",{type:"confirm",initial:!1})))return consola.consola.info("Initialization cancelled."),!1;let t;if(await consola.consola.prompt("Use interactive setup?",{type:"confirm",initial:!0})){const s=await D();t=C(s)}else t=v();const l=(await nypm.detectPackageManager(e))?.name||"npm";consola.consola.info(`Detected package manager: ${l}`),await promises.writeFile(a,t,"utf-8"),consola.consola.success("Created basis.config.ts with dynamic configuration");try{const s=await pkgTypes.readPackageJSON(e),p=!!(s.workspaces||await utils.fileExists(pathe.resolve(e,"pnpm-workspace.yaml")));o?!s.devDependencies?.["@funish/basis"]&&!s.dependencies?.["@funish/basis"]&&(s.devDependencies=s.devDependencies||{},s.devDependencies["@funish/basis"]="latest",consola.consola.info("Added @funish/basis to devDependencies")):(await nypm.addDevDependency("@funish/basis",{cwd:e,silent:!1,workspace:p}),consola.consola.success("Added @funish/basis to devDependencies"));const r="basis git --setup";s.scripts=s.scripts||{},l==="pnpm"?s.scripts.postinstall?s.scripts.postinstall.includes(r)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${r}`):s.scripts.postinstall=r:l==="yarn"?s.scripts.prepare?s.scripts.prepare.includes(r)||(s.scripts.prepare=`${s.scripts.prepare} && ${r}`):s.scripts.prepare=r:s.scripts.postinstall?s.scripts.postinstall.includes(r)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${r}`):s.scripts.postinstall=r,await pkgTypes.writePackageJSON(pathe.resolve(e,"package.json"),s),consola.consola.success(`Updated package.json scripts${o?" and dependencies":""}`),o?(consola.consola.info("Skipped dependency installation"),consola.consola.info("Run your package manager's install command to complete setup")):(consola.consola.start("Installing dependencies..."),await nypm.installDependencies({cwd:e,silent:!1}),consola.consola.success("Dependencies installed successfully"))}catch(s){return consola.consola.error("Failed to setup dependencies:",s),!1}return consola.consola.success("Basis initialization completed!"),consola.consola.info("You can now:"),consola.consola.info(" - Edit basis.config.ts to customize your configuration"),consola.consola.info(" - Run `basis git setup` to install git hooks"),!0}function previewBasisConfig(e={}){return C(e)}function createMinimalConfig(){const e=magicast.parseModule("export default defineBasisConfig({})"),i=e.exports.default.$args[0];i.lint={staged:{}},i.git={hooks:{},commitMsg:{}},e.imports.$prepend({from:"@funish/basis",imported:"defineBasisConfig"});const{code:n}=magicast.generateCode(e);return n}exports.createMinimalConfig=createMinimalConfig,exports.init=init,exports.previewBasisConfig=previewBasisConfig;
@@ -0,0 +1,3 @@
1
+ import{execSync as p}from"node:child_process";import{readdir as C,stat as N}from"node:fs/promises";import{consola as e}from"consola";import v from"micromatch";import{detectPackageManager as O}from"nypm";import{resolve as w,join as P}from"pathe";import{readPackageJSON as q}from"pkg-types";import{l as m,f as y}from"./basis.C7U9rUSl.mjs";function j(){try{const t=p("git diff --cached --name-only",{encoding:"utf8"}).trim().split(`
2
+ `).filter(Boolean),s=p("git diff --cached --name-only --diff-filter=D",{encoding:"utf8"}),c=new Set(s.trim().split(`
3
+ `).filter(Boolean));return t.filter(i=>!c.has(i))}catch{return[]}}async function E(t,s=["**/*"],c=["node_modules/**","dist/**","build/**",".git/**"]){const i=[];async function o(n,r=0){if(!(r>10))try{const u=await C(n);for(const g of u){const a=P(n,g),d=a.replace(`${t}/`,"");if(c.some(l=>v.isMatch(d,l)))continue;const f=await N(a);f.isDirectory()?await o(a,r+1):f.isFile()&&s.some(l=>v.isMatch(d,l))&&i.push(d)}}catch{}}return await o(t),i}async function F(t=process.cwd(),s){const{config:c}=await m({cwd:t,overrides:s?{lint:{staged:s}}:void 0}),i=c.lint?.staged||{},o=j();if(o.length===0)return e.info("No staged files to lint"),!0;if(Object.keys(i).length===0)return e.warn("No staged lint configuration found"),!0;let n=!1;const r=new Set;for(const[u,g]of Object.entries(i)){const a=o.filter(d=>!r.has(d)&&v.isMatch(d.split("/").pop()||d,u));if(a.length!==0){e.start(`Linting ${a.length} files: ${u}`);try{const d=`${g} ${a.join(" ")}`;p(d,{stdio:"inherit",cwd:t});const f=[];for(const l of a)await y(w(t,l))&&f.push(l);f.length>0&&p(`git add ${f.join(" ")}`,{stdio:"inherit",cwd:t}),a.forEach(l=>r.add(l)),e.success(`\u2713 ${u}`)}catch(d){n=!0,e.error(`\u2717 ${u} failed:`,d)}}}return!n}async function b(t=process.cwd(),s){const{config:c}=await m({cwd:t,overrides:s?{lint:{project:s}}:void 0}),i=c.lint?.project||{};if(Object.keys(i).length===0)return e.warn("No project lint configuration found"),!0;e.start("Running project-wide linting...");let o=!1;for(const[n,r]of Object.entries(i)){e.start(`Running project lint: ${n}`);try{p(r,{stdio:"inherit",cwd:t}),e.success(`\u2713 ${n}`)}catch(u){o=!0,e.error(`\u2717 ${n} failed:`,u)}}return!o}async function A(t=process.cwd(),s){const{config:c}=await m({cwd:t,overrides:s?{lint:{dependencies:s}}:void 0}),i=c.lint?.dependencies||{};let o=!1;try{const n=await q(t),r={...n.dependencies,...n.devDependencies},u=(await O(t))?.name||"npm",g=G(u);if(e.start("Checking dependencies..."),i.blockedPackages&&i.blockedPackages.length>0){const a=Object.keys(r).filter(d=>i.blockedPackages?.includes(d));a.length>0?(e.error(`\u2717 Blocked packages found: ${a.join(", ")}`),o=!0):e.success("\u2713 No blocked packages found")}if(i.checkOutdated)try{p(g.outdated,{cwd:t,stdio:"pipe"}),e.success("\u2713 All dependencies are up to date")}catch(a){e.warn("\u26A0 Some dependencies are outdated:",a)}if(i.checkSecurity)try{p(g.audit,{cwd:t,stdio:"pipe"}),e.success("\u2713 No security vulnerabilities found")}catch(a){e.error("\u2717 Security vulnerabilities detected:",a),o=!0}i.allowedLicenses&&i.allowedLicenses.length>0&&e.info("\u{1F4DD} License checking requires manual review or additional tooling")}catch(n){e.error("Failed to check dependencies:",n),o=!0}return!o}async function R(t=process.cwd(),s){const{config:c}=await m({cwd:t,overrides:s?{lint:{structure:s}}:void 0}),i=c.lint?.structure||{};let o=!1;if(e.start("Checking project structure..."),i.requiredFiles)for(const n of i.requiredFiles){const r=w(t,n);await y(r)?e.success(`\u2713 Required file found: ${n}`):(e.error(`\u2717 Required file missing: ${n}`),o=!0)}if(i.requiredDirs)for(const n of i.requiredDirs){const r=w(t,n);await y(r)?e.success(`\u2713 Required directory found: ${n}`):(e.error(`\u2717 Required directory missing: ${n}`),o=!0)}if(i.naming&&i.naming.length>0)for(const n of i.naming){const{path:r,files:u,directories:g,description:a}=n;e.start(`Checking naming rule: ${a||r}`);const d=await E(t,[r]);if(u){const f=new RegExp(u),l=d.filter(k=>{const h=k.split("/").pop()||"";return!f.test(h)});l.length>0?(e.error(`\u2717 Files with invalid naming in ${r}: ${l.slice(0,3).join(", ")}${l.length>3?"...":""}`),o=!0):d.length>0&&e.success(`\u2713 All files in ${r} follow naming convention`)}if(g){const f=new RegExp(g),l=new Set;d.forEach(h=>{const $=h.split("/");$.pop(),$.forEach(S=>l.add(S))});const k=Array.from(l).filter(h=>!f.test(h));k.length>0?(e.error(`\u2717 Directories with invalid naming in ${r}: ${k.slice(0,3).join(", ")}`),o=!0):l.size>0&&e.success(`\u2713 All directories in ${r} follow naming convention`)}}return!o}async function D(t=process.cwd(),s){const{config:c}=await m({cwd:t,overrides:s?{lint:{docs:s}}:void 0}),i=c.lint?.docs||{};let o=!1;if(e.start("Checking documentation..."),i.checkReadme!==!1){const n=["README.md","README.rst","README.txt","readme.md"];(await Promise.all(n.map(r=>y(w(t,r))))).some(r=>r)?e.success("\u2713 README file found"):(e.error("\u2717 No README file found"),o=!0)}if(i.checkChangelog){const n=["CHANGELOG.md","CHANGELOG.rst","HISTORY.md","changelog.md"];(await Promise.all(n.map(r=>y(w(t,r))))).some(r=>r)?e.success("\u2713 CHANGELOG file found"):(e.error("\u2717 No CHANGELOG file found"),o=!0)}return!o}async function M(t=process.cwd()){const{config:s}=await m({cwd:t}),c=s.lint||{};e.start("Running comprehensive project lint...");const i=(await Promise.allSettled([b(t,c.project),A(t,c.dependencies),R(t,c.structure),D(t,c.docs)])).filter(o=>o.status==="rejected"||o.status==="fulfilled"&&!o.value);return i.length===0?(e.success("\u2705 All lint checks passed!"),!0):(e.error(`\u274C ${i.length} lint check(s) failed`),!1)}function G(t){switch(t){case"yarn":return{outdated:"yarn outdated --json",audit:"yarn audit --level moderate"};case"pnpm":return{outdated:"pnpm outdated --format table",audit:"pnpm audit --audit-level moderate"};case"bun":return{outdated:"bun outdated",audit:"bun audit --audit-level moderate"};default:return{outdated:"npm outdated --json",audit:"npm audit --audit-level moderate"}}}export{b as a,A as b,R as c,D as d,M as e,E as f,j as g,F as l};
@@ -0,0 +1,10 @@
1
+ import{execSync as p}from"node:child_process";import{readFile as m,unlink as G,writeFile as w,copyFile as E}from"node:fs/promises";import{consola as r}from"consola";import b from"ini";import{parseModule as S,generateCode as x}from"magicast";import{resolve as l}from"pathe";import{l as d,f as g}from"./basis.C7U9rUSl.mjs";const I=["feat","fix","docs","style","refactor","perf","test","build","ci","chore","revert"];function $(o){const s=o.trim().split(`
2
+ `),i=s[0].match(/^(\w+)(\(([^)]+)\))?(!)?:\s*(.+)$/);if(!i)return null;const[,e,,t,c,a]=i,n=s.slice(1).find(f=>f.trim())?.trim(),u=s.slice(-1)[0]?.trim();return{type:e,scope:t,description:a,body:n,footer:u,isBreaking:!!c||o.includes("BREAKING CHANGE:")}}function F(o,s={}){const i=[],{types:e=I,maxLength:t=72,minLength:c=10,scopeRequired:a=!1,allowedScopes:n=[]}=s,u=$(o);if(!u)return{valid:!1,errors:["Invalid commit format. Expected: type(scope): description"]};e.includes(u.type)||i.push(`Invalid type '${u.type}'. Allowed: ${e.join(", ")}`);const f=o.split(`
3
+ `)[0];return f.length>t&&i.push(`Header too long (${f.length}). Max: ${t}`),f.length<c&&i.push(`Header too short (${f.length}). Min: ${c}`),a&&!u.scope&&i.push("Scope is required"),u.scope&&n.length>0&&!n.includes(u.scope)&&i.push(`Invalid scope '${u.scope}'. Allowed: ${n.join(", ")}`),{valid:i.length===0,errors:i}}async function M(o=process.cwd(),s){const{config:i}=await d({cwd:o,overrides:s?{git:{commitMsg:s}}:void 0}),e=i.git?.commitMsg||{};let t;try{const a=l(".git/COMMIT_EDITMSG");await g(a)?t=(await m(a)).toString("utf8"):t=p("git log -1 --pretty=%B",{encoding:"utf8"}).trim()}catch(a){return r.error("\u2717 Failed to read commit message:",a),!1}const c=F(t,e);return c.valid?(r.success("\u2713 Commit message is valid"),!0):(r.error("\u2717 Invalid commit message:"),c.errors.forEach(a=>r.error(` ${a}`)),!1)}async function j(o){const s=l(o,".git/config");if(!await g(s))return null;const i=new Date().toISOString().replace(/[:.]/g,"-"),e=l(o,`.git/config.backup.${i}`);try{return await E(s,e),r.info(`\u{1F4C4} Created backup: ${e}`),e}catch(t){return r.warn("Failed to create Git config backup:",t),null}}async function h(o=process.cwd()){const s=l(o,".git/config");if(!await g(s))return r.info("No .git/config found, will create new one"),{};try{const i=await m(s,"utf8"),e=b.parse(i);return r.success(`\u2713 Read existing Git configuration from ${s}`),e}catch(i){return r.warn("Failed to read .git/config:",i),{}}}async function y(o,s=process.cwd()){const i=l(s,".git/config");try{let e=b.stringify(o,{whitespace:!0});e=e.split(`
4
+ `).map(t=>t&&!t.startsWith("[")&&t.includes("=")?` ${t}`:t).join(`
5
+ `),await w(i,e,"utf8"),r.success(`\u2713 Git configuration written to ${i}`)}catch(e){throw r.error("Failed to write .git/config:",e),e}}function R(o){const s={};return o&&Object.entries(o).forEach(([i,e])=>{typeof e=="object"&&e!==null&&(s[i]||(s[i]={}),Object.entries(e).forEach(([t,c])=>{c!==void 0&&(s[i][t]=c)}))}),s}function N(o,s){const i={...o};return Object.entries(s).forEach(([e,t])=>{typeof t=="object"&&t!==null&&(i[e]||(i[e]={}),Object.entries(t).forEach(([c,a])=>{a!==void 0&&(i[e][c]=a,r.info(`\u{1F527} Setting ${e}.${c} = ${a}`))}))}),i}async function k(o=process.cwd(),s){const{config:i}=await d({cwd:o,overrides:s?{git:{config:s}}:void 0}),e=i.git?.config||{};if(Object.keys(e).length===0)return r.info("No Git configuration settings to apply"),!0;try{const t=await j(o),c=await h(o),a=R(e),n=N(c,a);return await y(n,o),r.success("\u2713 Git configuration setup completed"),t&&r.info(`\u{1F4BE} Original config backed up to: ${t.split("/").pop()}`),!0}catch(t){return r.error("\u2717 Failed to setup Git configuration:",t),!1}}async function B(o=process.cwd(),s=!0,i={}){try{const e=await j(o),t=await h(o);if(!t||Object.keys(t).length===0)return r.info("No Git configuration found to reset"),!0;const c={};if(s&&t.user&&(c.user=t.user,r.info("\u{1F512} Keeping user configuration (name, email)")),t.core){const a=["repositoryformatversion","filemode","bare","logallrefupdates"],n={};a.forEach(u=>{t.core[u]!==void 0&&(n[u]=t.core[u])}),Object.keys(n).length>0&&(c.core=n,r.info("\u{1F512} Keeping essential core Git settings"))}return await y(c,o),r.success("\u2713 Git configuration reset completed"),e&&r.info(`\u{1F4BE} Original config backed up to: ${e.split("/").pop()}`),i.updateConfig?await C(o,!1,!0):!0}catch(e){return r.error("\u2717 Failed to reset Git configuration:",e),!1}}async function v(o=process.cwd(),s){const{config:i}=await d({cwd:o,overrides:s?{git:{hooks:s}}:void 0}),e=i.git?.hooks||{},t=l(o,".git/hooks");if(!await g(t))return r.error("\u2717 Git hooks directory not found. Is this a Git repository?"),!1;let c=!0;for(const[a,n]of Object.entries(e)){const u=l(t,a);try{let f=`#!/bin/sh
6
+
7
+ `;if(typeof n=="string")f+=`${n}
8
+ `;else if(n&&typeof n=="object"&&"commands"in n){const O=n.commands;f+=`${O.join(`
9
+ `)}
10
+ `}await w(u,f,{mode:493}),r.success(`\u2713 Setup ${a} hook`)}catch(f){r.error(`\u2717 Failed to setup ${a} hook:`,f),c=!1}}return c}async function H(o=process.cwd()){try{try{p("git rev-parse --git-dir",{cwd:o,stdio:"pipe"}),r.info("Git repository already exists")}catch{p("git init",{cwd:o,stdio:"inherit"}),r.success("\u2713 Initialized Git repository")}const s=await k(o),i=await v(o);return s&&i}catch(s){return r.error("\u2717 Failed to initialize Git repository:",s),!1}}async function A(o=process.cwd()){const{config:s}=await d({cwd:o}),i=s.git||{};r.start("Setting up Git configuration...");const e=(await Promise.allSettled([k(o,i.config),v(o,i.hooks)])).filter(t=>t.status==="rejected"||t.status==="fulfilled"&&!t.value);return e.length===0?(r.success("\u2705 Git setup completed successfully!"),!0):(r.error(`\u274C ${e.length} Git setup step(s) failed`),!1)}async function C(o,s=!1,i=!1){const e=l(o,"basis.config.ts");if(!await g(e))return r.info("No basis.config.ts found to update"),!0;try{const t=await m(e,"utf8"),c=S(t),a=c.exports.default;if(!a||!a.$args?.[0])return r.warn("Could not parse basis.config.ts structure"),!1;const n=a.$args[0];n.git&&(s&&n.git.hooks&&(delete n.git.hooks,r.success("\u2713 Removed hooks configuration from basis.config.ts")),i&&n.git.config&&(delete n.git.config,r.success("\u2713 Removed git config from basis.config.ts")),Object.keys(n.git).length===0&&(delete n.git,r.success("\u2713 Removed empty git section from basis.config.ts")));const{code:u}=x(c);return await w(e,u,"utf8"),!0}catch(t){return r.error("\u2717 Failed to update basis.config.ts:",t),!1}}async function K(o=process.cwd(),s,i={}){const e=l(o,".git/hooks");if(!await g(e))return r.warn("Git hooks directory not found. Is this a Git repository?"),!0;let t=!0;if(s&&s.length>0)for(const c of s){const a=l(e,c);if(await g(a))try{await G(a),r.success(`\u2713 Removed ${c} hook`)}catch(n){r.error(`\u2717 Failed to remove ${c} hook:`,n),t=!1}}else{const{config:c}=await d({cwd:o}),a=c.git?.hooks||{};for(const n of Object.keys(a)){const u=l(e,n);if(await g(u))try{await G(u),r.success(`\u2713 Removed ${n} hook`)}catch(f){r.error(`\u2717 Failed to remove ${n} hook:`,f),t=!1}}if(i.updateConfig){const n=await C(o,!0,!1);t=t&&n}}return t}export{k as a,A as b,B as c,h as d,H as i,M as l,$ as p,K as r,v as s,F as v,y as w};
@@ -0,0 +1 @@
1
+ import{writeFile as b}from"node:fs/promises";import{consola as t}from"consola";import{parseModule as f,generateCode as m,builders as y}from"magicast";import{detectPackageManager as k,addDevDependency as h,installDependencies as x}from"nypm";import{resolve as d}from"pathe";import{readPackageJSON as C,writePackageJSON as $}from"pkg-types";import{f as u}from"./basis.C7U9rUSl.mjs";function v(){const i=f("export default {}"),n=y.functionCall("defineBasisConfig",[{}]),a={staged:{},project:{}},c={hooks:{}},o=n.$args[0];o.lint=a,o.git=c,i.exports.default=n,i.imports.$prepend({from:"@funish/basis",imported:"defineBasisConfig"});const{code:r}=m(i);return r}function g(i){const{enableStagedLinting:n=!1,enableCommitMsgLinting:a=!1,customLintPatterns:c,customExcludePatterns:o}=i,r=f("export default defineBasisConfig({})"),e=r.exports.default.$args[0];e.lint={},e.lint.staged={},n&&(e.lint.staged["*.{js,ts,jsx,tsx}"]="eslint --fix",e.lint.staged["*.{css,scss,less}"]="stylelint --fix"),e.lint.project={patterns:c||["src/**/*","lib/**/*","*.{js,ts,jsx,tsx}"],exclude:o||["node_modules/**","dist/**","build/**"]},e.git={},e.git.hooks={},n&&(e.git.hooks["pre-commit"]="basis lint --staged"),a&&(e.git.hooks["commit-msg"]="basis git --lint-commit"),e.git.commitMsg={},r.imports.$items.some(s=>s.from==="@funish/basis")||r.imports.$prepend({from:"@funish/basis",imported:"defineBasisConfig"});const{code:l}=m(r);return l}async function D(){const i=await t.prompt("Enable staged files linting?",{type:"confirm",initial:!0}),n=await t.prompt("Enable commit message linting?",{type:"confirm",initial:!0});let a;if(await t.prompt("Customize lint file patterns?",{type:"confirm",initial:!1})){const c=await t.prompt("Enter lint patterns (comma-separated):",{type:"text",initial:"src/**/*,lib/**/*,*.{js,ts,jsx,tsx}"});typeof c=="string"&&(a=c.split(",").map(o=>o.trim()))}return{enableStagedLinting:i,enableCommitMsgLinting:n,customLintPatterns:a}}async function j(i=process.cwd(),n={}){const{force:a=!1,skipGitCheck:c=!1,skipInstall:o=!1}=n;t.start("Initializing basis configuration...");const r=d(i,"basis.config.ts");if(await u(r)&&!a)return t.error("basis.config.ts already exists. Use --force to overwrite."),!1;if(!c&&!await u(d(i,".git"))&&(t.warn("No .git directory found. Git hooks will not work properly."),!await t.prompt("Continue anyway?",{type:"confirm",initial:!1})))return t.info("Initialization cancelled."),!1;let e;if(await t.prompt("Use interactive setup?",{type:"confirm",initial:!0})){const s=await D();e=g(s)}else e=v();const l=(await k(i))?.name||"npm";t.info(`Detected package manager: ${l}`),await b(r,e,"utf-8"),t.success("Created basis.config.ts with dynamic configuration");try{const s=await C(i),w=!!(s.workspaces||await u(d(i,"pnpm-workspace.yaml")));o?!s.devDependencies?.["@funish/basis"]&&!s.dependencies?.["@funish/basis"]&&(s.devDependencies=s.devDependencies||{},s.devDependencies["@funish/basis"]="latest",t.info("Added @funish/basis to devDependencies")):(await h("@funish/basis",{cwd:i,silent:!1,workspace:w}),t.success("Added @funish/basis to devDependencies"));const p="basis git --setup";s.scripts=s.scripts||{},l==="pnpm"?s.scripts.postinstall?s.scripts.postinstall.includes(p)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${p}`):s.scripts.postinstall=p:l==="yarn"?s.scripts.prepare?s.scripts.prepare.includes(p)||(s.scripts.prepare=`${s.scripts.prepare} && ${p}`):s.scripts.prepare=p:s.scripts.postinstall?s.scripts.postinstall.includes(p)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${p}`):s.scripts.postinstall=p,await $(d(i,"package.json"),s),t.success(`Updated package.json scripts${o?" and dependencies":""}`),o?(t.info("Skipped dependency installation"),t.info("Run your package manager's install command to complete setup")):(t.start("Installing dependencies..."),await x({cwd:i,silent:!1}),t.success("Dependencies installed successfully"))}catch(s){return t.error("Failed to setup dependencies:",s),!1}return t.success("Basis initialization completed!"),t.info("You can now:"),t.info(" - Edit basis.config.ts to customize your configuration"),t.info(" - Run `basis git setup` to install git hooks"),!0}function B(i={}){return g(i)}function M(){const i=f("export default defineBasisConfig({})"),n=i.exports.default.$args[0];n.lint={staged:{}},n.git={hooks:{},commitMsg:{}},i.imports.$prepend({from:"@funish/basis",imported:"defineBasisConfig"});const{code:a}=m(i);return a}export{M as c,j as i,B as p};
@@ -0,0 +1 @@
1
+ "use strict";const promises=require("node:fs/promises"),c12=require("c12"),config=require("../config.cjs");async function loadConfig(s={}){return await c12.loadConfig({name:"basis",cwd:process.cwd(),...s,defaults:{...config.defaultConfig,...s.defaults}})}async function fileExists(s){try{return await promises.access(s),!0}catch{return!1}}exports.fileExists=fileExists,exports.loadConfig=loadConfig;
@@ -0,0 +1,3 @@
1
+ "use strict";const node_child_process=require("node:child_process"),promises=require("node:fs/promises"),consola=require("consola"),w=require("micromatch"),nypm=require("nypm"),pathe=require("pathe"),pkgTypes=require("pkg-types"),utils=require("./basis.DcyVtmjR.cjs");function _interopDefaultCompat(e){return e&&typeof e=="object"&&"default"in e?e.default:e}const w__default=_interopDefaultCompat(w);function getStagedFiles(){try{const e=node_child_process.execSync("git diff --cached --name-only",{encoding:"utf8"}).trim().split(`
2
+ `).filter(Boolean),s=node_child_process.execSync("git diff --cached --name-only --diff-filter=D",{encoding:"utf8"}),c=new Set(s.trim().split(`
3
+ `).filter(Boolean));return e.filter(t=>!c.has(t))}catch{return[]}}async function getProjectFiles(e,s=["**/*"],c=["node_modules/**","dist/**","build/**",".git/**"]){const t=[];async function i(n,o=0){if(!(o>10))try{const d=await promises.readdir(n);for(const f of d){const r=pathe.join(n,f),a=r.replace(`${e}/`,"");if(c.some(l=>w__default.isMatch(a,l)))continue;const u=await promises.stat(r);u.isDirectory()?await i(r,o+1):u.isFile()&&s.some(l=>w__default.isMatch(a,l))&&t.push(a)}}catch{}}return await i(e),t}async function lintStaged(e=process.cwd(),s){const{config:c}=await utils.loadConfig({cwd:e,overrides:s?{lint:{staged:s}}:void 0}),t=c.lint?.staged||{},i=getStagedFiles();if(i.length===0)return consola.consola.info("No staged files to lint"),!0;if(Object.keys(t).length===0)return consola.consola.warn("No staged lint configuration found"),!0;let n=!1;const o=new Set;for(const[d,f]of Object.entries(t)){const r=i.filter(a=>!o.has(a)&&w__default.isMatch(a.split("/").pop()||a,d));if(r.length!==0){consola.consola.start(`Linting ${r.length} files: ${d}`);try{const a=`${f} ${r.join(" ")}`;node_child_process.execSync(a,{stdio:"inherit",cwd:e});const u=[];for(const l of r)await utils.fileExists(pathe.resolve(e,l))&&u.push(l);u.length>0&&node_child_process.execSync(`git add ${u.join(" ")}`,{stdio:"inherit",cwd:e}),r.forEach(l=>o.add(l)),consola.consola.success(`\u2713 ${d}`)}catch(a){n=!0,consola.consola.error(`\u2717 ${d} failed:`,a)}}}return!n}async function lintProject(e=process.cwd(),s){const{config:c}=await utils.loadConfig({cwd:e,overrides:s?{lint:{project:s}}:void 0}),t=c.lint?.project||{};if(Object.keys(t).length===0)return consola.consola.warn("No project lint configuration found"),!0;consola.consola.start("Running project-wide linting...");let i=!1;for(const[n,o]of Object.entries(t)){consola.consola.start(`Running project lint: ${n}`);try{node_child_process.execSync(o,{stdio:"inherit",cwd:e}),consola.consola.success(`\u2713 ${n}`)}catch(d){i=!0,consola.consola.error(`\u2717 ${n} failed:`,d)}}return!i}async function lintDependencies(e=process.cwd(),s){const{config:c}=await utils.loadConfig({cwd:e,overrides:s?{lint:{dependencies:s}}:void 0}),t=c.lint?.dependencies||{};let i=!1;try{const n=await pkgTypes.readPackageJSON(e),o={...n.dependencies,...n.devDependencies},d=(await nypm.detectPackageManager(e))?.name||"npm",f=F(d);if(consola.consola.start("Checking dependencies..."),t.blockedPackages&&t.blockedPackages.length>0){const r=Object.keys(o).filter(a=>t.blockedPackages?.includes(a));r.length>0?(consola.consola.error(`\u2717 Blocked packages found: ${r.join(", ")}`),i=!0):consola.consola.success("\u2713 No blocked packages found")}if(t.checkOutdated)try{node_child_process.execSync(f.outdated,{cwd:e,stdio:"pipe"}),consola.consola.success("\u2713 All dependencies are up to date")}catch(r){consola.consola.warn("\u26A0 Some dependencies are outdated:",r)}if(t.checkSecurity)try{node_child_process.execSync(f.audit,{cwd:e,stdio:"pipe"}),consola.consola.success("\u2713 No security vulnerabilities found")}catch(r){consola.consola.error("\u2717 Security vulnerabilities detected:",r),i=!0}t.allowedLicenses&&t.allowedLicenses.length>0&&consola.consola.info("\u{1F4DD} License checking requires manual review or additional tooling")}catch(n){consola.consola.error("Failed to check dependencies:",n),i=!0}return!i}async function lintStructure(e=process.cwd(),s){const{config:c}=await utils.loadConfig({cwd:e,overrides:s?{lint:{structure:s}}:void 0}),t=c.lint?.structure||{};let i=!1;if(consola.consola.start("Checking project structure..."),t.requiredFiles)for(const n of t.requiredFiles){const o=pathe.resolve(e,n);await utils.fileExists(o)?consola.consola.success(`\u2713 Required file found: ${n}`):(consola.consola.error(`\u2717 Required file missing: ${n}`),i=!0)}if(t.requiredDirs)for(const n of t.requiredDirs){const o=pathe.resolve(e,n);await utils.fileExists(o)?consola.consola.success(`\u2713 Required directory found: ${n}`):(consola.consola.error(`\u2717 Required directory missing: ${n}`),i=!0)}if(t.naming&&t.naming.length>0)for(const n of t.naming){const{path:o,files:d,directories:f,description:r}=n;consola.consola.start(`Checking naming rule: ${r||o}`);const a=await getProjectFiles(e,[o]);if(d){const u=new RegExp(d),l=a.filter(p=>{const g=p.split("/").pop()||"";return!u.test(g)});l.length>0?(consola.consola.error(`\u2717 Files with invalid naming in ${o}: ${l.slice(0,3).join(", ")}${l.length>3?"...":""}`),i=!0):a.length>0&&consola.consola.success(`\u2713 All files in ${o} follow naming convention`)}if(f){const u=new RegExp(f),l=new Set;a.forEach(g=>{const h=g.split("/");h.pop(),h.forEach(m=>l.add(m))});const p=Array.from(l).filter(g=>!u.test(g));p.length>0?(consola.consola.error(`\u2717 Directories with invalid naming in ${o}: ${p.slice(0,3).join(", ")}`),i=!0):l.size>0&&consola.consola.success(`\u2713 All directories in ${o} follow naming convention`)}}return!i}async function lintDocs(e=process.cwd(),s){const{config:c}=await utils.loadConfig({cwd:e,overrides:s?{lint:{docs:s}}:void 0}),t=c.lint?.docs||{};let i=!1;if(consola.consola.start("Checking documentation..."),t.checkReadme!==!1){const n=["README.md","README.rst","README.txt","readme.md"];(await Promise.all(n.map(o=>utils.fileExists(pathe.resolve(e,o))))).some(o=>o)?consola.consola.success("\u2713 README file found"):(consola.consola.error("\u2717 No README file found"),i=!0)}if(t.checkChangelog){const n=["CHANGELOG.md","CHANGELOG.rst","HISTORY.md","changelog.md"];(await Promise.all(n.map(o=>utils.fileExists(pathe.resolve(e,o))))).some(o=>o)?consola.consola.success("\u2713 CHANGELOG file found"):(consola.consola.error("\u2717 No CHANGELOG file found"),i=!0)}return!i}async function lintAll(e=process.cwd()){const{config:s}=await utils.loadConfig({cwd:e}),c=s.lint||{};consola.consola.start("Running comprehensive project lint...");const t=(await Promise.allSettled([lintProject(e,c.project),lintDependencies(e,c.dependencies),lintStructure(e,c.structure),lintDocs(e,c.docs)])).filter(i=>i.status==="rejected"||i.status==="fulfilled"&&!i.value);return t.length===0?(consola.consola.success("\u2705 All lint checks passed!"),!0):(consola.consola.error(`\u274C ${t.length} lint check(s) failed`),!1)}function F(e){switch(e){case"yarn":return{outdated:"yarn outdated --json",audit:"yarn audit --level moderate"};case"pnpm":return{outdated:"pnpm outdated --format table",audit:"pnpm audit --audit-level moderate"};case"bun":return{outdated:"bun outdated",audit:"bun audit --audit-level moderate"};default:return{outdated:"npm outdated --json",audit:"npm audit --audit-level moderate"}}}exports.getProjectFiles=getProjectFiles,exports.getStagedFiles=getStagedFiles,exports.lintAll=lintAll,exports.lintDependencies=lintDependencies,exports.lintDocs=lintDocs,exports.lintProject=lintProject,exports.lintStaged=lintStaged,exports.lintStructure=lintStructure;
@@ -0,0 +1,10 @@
1
+ "use strict";const node_child_process=require("node:child_process"),promises=require("node:fs/promises"),consola=require("consola"),G=require("ini"),magicast=require("magicast"),pathe=require("pathe"),utils=require("./basis.DcyVtmjR.cjs");function _interopDefaultCompat(o){return o&&typeof o=="object"&&"default"in o?o.default:o}const G__default=_interopDefaultCompat(G),P=["feat","fix","docs","style","refactor","perf","test","build","ci","chore","revert"];function parseCommitMessage(o){const i=o.trim().split(`
2
+ `),s=i[0].match(/^(\w+)(\(([^)]+)\))?(!)?:\s*(.+)$/);if(!s)return null;const[,e,,t,r,c]=s,n=i.slice(1).find(l=>l.trim())?.trim(),a=i.slice(-1)[0]?.trim();return{type:e,scope:t,description:c,body:n,footer:a,isBreaking:!!r||o.includes("BREAKING CHANGE:")}}function validateCommitMessage(o,i={}){const s=[],{types:e=P,maxLength:t=72,minLength:r=10,scopeRequired:c=!1,allowedScopes:n=[]}=i,a=parseCommitMessage(o);if(!a)return{valid:!1,errors:["Invalid commit format. Expected: type(scope): description"]};e.includes(a.type)||s.push(`Invalid type '${a.type}'. Allowed: ${e.join(", ")}`);const l=o.split(`
3
+ `)[0];return l.length>t&&s.push(`Header too long (${l.length}). Max: ${t}`),l.length<r&&s.push(`Header too short (${l.length}). Min: ${r}`),c&&!a.scope&&s.push("Scope is required"),a.scope&&n.length>0&&!n.includes(a.scope)&&s.push(`Invalid scope '${a.scope}'. Allowed: ${n.join(", ")}`),{valid:s.length===0,errors:s}}async function lintCommitMessage(o=process.cwd(),i){const{config:s}=await utils.loadConfig({cwd:o,overrides:i?{git:{commitMsg:i}}:void 0}),e=s.git?.commitMsg||{};let t;try{const c=pathe.resolve(".git/COMMIT_EDITMSG");await utils.fileExists(c)?t=(await promises.readFile(c)).toString("utf8"):t=node_child_process.execSync("git log -1 --pretty=%B",{encoding:"utf8"}).trim()}catch(c){return consola.consola.error("\u2717 Failed to read commit message:",c),!1}const r=validateCommitMessage(t,e);return r.valid?(consola.consola.success("\u2713 Commit message is valid"),!0):(consola.consola.error("\u2717 Invalid commit message:"),r.errors.forEach(c=>consola.consola.error(` ${c}`)),!1)}async function k(o){const i=pathe.resolve(o,".git/config");if(!await utils.fileExists(i))return null;const s=new Date().toISOString().replace(/[:.]/g,"-"),e=pathe.resolve(o,`.git/config.backup.${s}`);try{return await promises.copyFile(i,e),consola.consola.info(`\u{1F4C4} Created backup: ${e}`),e}catch(t){return consola.consola.warn("Failed to create Git config backup:",t),null}}async function readGitConfig(o=process.cwd()){const i=pathe.resolve(o,".git/config");if(!await utils.fileExists(i))return consola.consola.info("No .git/config found, will create new one"),{};try{const s=await promises.readFile(i,"utf8"),e=G__default.parse(s);return consola.consola.success(`\u2713 Read existing Git configuration from ${i}`),e}catch(s){return consola.consola.warn("Failed to read .git/config:",s),{}}}async function writeGitConfig(o,i=process.cwd()){const s=pathe.resolve(i,".git/config");try{let e=G__default.stringify(o,{whitespace:!0});e=e.split(`
4
+ `).map(t=>t&&!t.startsWith("[")&&t.includes("=")?` ${t}`:t).join(`
5
+ `),await promises.writeFile(s,e,"utf8"),consola.consola.success(`\u2713 Git configuration written to ${s}`)}catch(e){throw consola.consola.error("Failed to write .git/config:",e),e}}function x(o){const i={};return o&&Object.entries(o).forEach(([s,e])=>{typeof e=="object"&&e!==null&&(i[s]||(i[s]={}),Object.entries(e).forEach(([t,r])=>{r!==void 0&&(i[s][t]=r)}))}),i}function S(o,i){const s={...o};return Object.entries(i).forEach(([e,t])=>{typeof t=="object"&&t!==null&&(s[e]||(s[e]={}),Object.entries(t).forEach(([r,c])=>{c!==void 0&&(s[e][r]=c,consola.consola.info(`\u{1F527} Setting ${e}.${r} = ${c}`))}))}),s}async function setupGitConfig(o=process.cwd(),i){const{config:s}=await utils.loadConfig({cwd:o,overrides:i?{git:{config:i}}:void 0}),e=s.git?.config||{};if(Object.keys(e).length===0)return consola.consola.info("No Git configuration settings to apply"),!0;try{const t=await k(o),r=await readGitConfig(o),c=x(e),n=S(r,c);return await writeGitConfig(n,o),consola.consola.success("\u2713 Git configuration setup completed"),t&&consola.consola.info(`\u{1F4BE} Original config backed up to: ${t.split("/").pop()}`),!0}catch(t){return consola.consola.error("\u2717 Failed to setup Git configuration:",t),!1}}async function resetGitConfig(o=process.cwd(),i=!0,s={}){try{const e=await k(o),t=await readGitConfig(o);if(!t||Object.keys(t).length===0)return consola.consola.info("No Git configuration found to reset"),!0;const r={};if(i&&t.user&&(r.user=t.user,consola.consola.info("\u{1F512} Keeping user configuration (name, email)")),t.core){const c=["repositoryformatversion","filemode","bare","logallrefupdates"],n={};c.forEach(a=>{t.core[a]!==void 0&&(n[a]=t.core[a])}),Object.keys(n).length>0&&(r.core=n,consola.consola.info("\u{1F512} Keeping essential core Git settings"))}return await writeGitConfig(r,o),consola.consola.success("\u2713 Git configuration reset completed"),e&&consola.consola.info(`\u{1F4BE} Original config backed up to: ${e.split("/").pop()}`),s.updateConfig?await b(o,!1,!0):!0}catch(e){return consola.consola.error("\u2717 Failed to reset Git configuration:",e),!1}}async function setupGitHooks(o=process.cwd(),i){const{config:s}=await utils.loadConfig({cwd:o,overrides:i?{git:{hooks:i}}:void 0}),e=s.git?.hooks||{},t=pathe.resolve(o,".git/hooks");if(!await utils.fileExists(t))return consola.consola.error("\u2717 Git hooks directory not found. Is this a Git repository?"),!1;let r=!0;for(const[c,n]of Object.entries(e)){const a=pathe.resolve(t,c);try{let l=`#!/bin/sh
6
+
7
+ `;if(typeof n=="string")l+=`${n}
8
+ `;else if(n&&typeof n=="object"&&"commands"in n){const u=n.commands;l+=`${u.join(`
9
+ `)}
10
+ `}await promises.writeFile(a,l,{mode:493}),consola.consola.success(`\u2713 Setup ${c} hook`)}catch(l){consola.consola.error(`\u2717 Failed to setup ${c} hook:`,l),r=!1}}return r}async function initGitRepo(o=process.cwd()){try{try{node_child_process.execSync("git rev-parse --git-dir",{cwd:o,stdio:"pipe"}),consola.consola.info("Git repository already exists")}catch{node_child_process.execSync("git init",{cwd:o,stdio:"inherit"}),consola.consola.success("\u2713 Initialized Git repository")}const i=await setupGitConfig(o),s=await setupGitHooks(o);return i&&s}catch(i){return consola.consola.error("\u2717 Failed to initialize Git repository:",i),!1}}async function setupGit(o=process.cwd()){const{config:i}=await utils.loadConfig({cwd:o}),s=i.git||{};consola.consola.start("Setting up Git configuration...");const e=(await Promise.allSettled([setupGitConfig(o,s.config),setupGitHooks(o,s.hooks)])).filter(t=>t.status==="rejected"||t.status==="fulfilled"&&!t.value);return e.length===0?(consola.consola.success("\u2705 Git setup completed successfully!"),!0):(consola.consola.error(`\u274C ${e.length} Git setup step(s) failed`),!1)}async function b(o,i=!1,s=!1){const e=pathe.resolve(o,"basis.config.ts");if(!await utils.fileExists(e))return consola.consola.info("No basis.config.ts found to update"),!0;try{const t=await promises.readFile(e,"utf8"),r=magicast.parseModule(t),c=r.exports.default;if(!c||!c.$args?.[0])return consola.consola.warn("Could not parse basis.config.ts structure"),!1;const n=c.$args[0];n.git&&(i&&n.git.hooks&&(delete n.git.hooks,consola.consola.success("\u2713 Removed hooks configuration from basis.config.ts")),s&&n.git.config&&(delete n.git.config,consola.consola.success("\u2713 Removed git config from basis.config.ts")),Object.keys(n.git).length===0&&(delete n.git,consola.consola.success("\u2713 Removed empty git section from basis.config.ts")));const{code:a}=magicast.generateCode(r);return await promises.writeFile(e,a,"utf8"),!0}catch(t){return consola.consola.error("\u2717 Failed to update basis.config.ts:",t),!1}}async function removeGitHooks(o=process.cwd(),i,s={}){const e=pathe.resolve(o,".git/hooks");if(!await utils.fileExists(e))return consola.consola.warn("Git hooks directory not found. Is this a Git repository?"),!0;let t=!0;if(i&&i.length>0)for(const r of i){const c=pathe.resolve(e,r);if(await utils.fileExists(c))try{await promises.unlink(c),consola.consola.success(`\u2713 Removed ${r} hook`)}catch(n){consola.consola.error(`\u2717 Failed to remove ${r} hook:`,n),t=!1}}else{const{config:r}=await utils.loadConfig({cwd:o}),c=r.git?.hooks||{};for(const n of Object.keys(c)){const a=pathe.resolve(e,n);if(await utils.fileExists(a))try{await promises.unlink(a),consola.consola.success(`\u2713 Removed ${n} hook`)}catch(l){consola.consola.error(`\u2717 Failed to remove ${n} hook:`,l),t=!1}}if(s.updateConfig){const n=await b(o,!0,!1);t=t&&n}}return t}exports.initGitRepo=initGitRepo,exports.lintCommitMessage=lintCommitMessage,exports.parseCommitMessage=parseCommitMessage,exports.readGitConfig=readGitConfig,exports.removeGitHooks=removeGitHooks,exports.resetGitConfig=resetGitConfig,exports.setupGit=setupGit,exports.setupGitConfig=setupGitConfig,exports.setupGitHooks=setupGitHooks,exports.validateCommitMessage=validateCommitMessage,exports.writeGitConfig=writeGitConfig;
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@funish/basis",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "A unified development toolkit with CLI for package management, versioning, publishing, linting, and git hooks management for JavaScript/TypeScript projects.",
5
5
  "main": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
7
7
  "files": [
8
- "dist",
9
- "templates"
8
+ "dist"
10
9
  ],
11
10
  "bin": {
12
11
  "basis": "dist/cli.mjs"
@@ -61,6 +60,8 @@
61
60
  "c12": "3.0.4",
62
61
  "citty": "0.1.6",
63
62
  "consola": "3.4.2",
63
+ "ini": "5.0.0",
64
+ "magicast": "0.3.5",
64
65
  "micromatch": "4.0.8",
65
66
  "nypm": "0.6.0",
66
67
  "pathe": "2.0.3",
@@ -68,6 +69,7 @@
68
69
  "semver": "7.7.2"
69
70
  },
70
71
  "devDependencies": {
72
+ "@types/ini": "4.1.1",
71
73
  "@types/micromatch": "4.0.9",
72
74
  "@types/semver": "7.7.0"
73
75
  },
@@ -1 +0,0 @@
1
- "use strict";const citty=require("citty"),consola=require("consola"),githooks$1=require("../shared/basis.DeKfEQsQ.cjs");require("node:child_process"),require("node:fs/promises"),require("pathe"),require("../shared/basis.CSSuyvpq.cjs"),require("c12"),require("../config.cjs");const githooks=citty.defineCommand({meta:{name:"hooks",description:"Manage git hooks"},subCommands:{install:citty.defineCommand({meta:{name:"install",description:"Install git hooks"},args:{"auto-init-git":{type:"boolean",description:"Automatically initialize git repository if not found"},"skip-git-check":{type:"boolean",description:"Skip git command availability check"},force:{type:"boolean",alias:"f",description:"Force operation even if git is not available"}},async run({args:i}){try{let o;(i["auto-init-git"]!==void 0||i["skip-git-check"]!==void 0||i.force!==void 0)&&(o={},i["auto-init-git"]!==void 0&&(o.autoInitGit=!!i["auto-init-git"]),i["skip-git-check"]!==void 0&&(o.skipGitCheck=!!i["skip-git-check"]),i.force!==void 0&&(o.force=!!i.force)),await githooks$1.installHooks(process.cwd(),o)}catch(o){consola.consola.error("Failed to install hooks:",o),process.exit(1)}}}),uninstall:citty.defineCommand({meta:{name:"uninstall",description:"Uninstall git hooks"},args:{"skip-git-check":{type:"boolean",description:"Skip git command availability check"},force:{type:"boolean",alias:"f",description:"Force operation even if git is not available"}},async run({args:i}){try{let o;(i["skip-git-check"]!==void 0||i.force!==void 0)&&(o={},i["skip-git-check"]!==void 0&&(o.skipGitCheck=!!i["skip-git-check"]),i.force!==void 0&&(o.force=!!i.force)),await githooks$1.uninstallHooks(process.cwd(),o)}catch(o){consola.consola.error("Failed to uninstall hooks:",o),process.exit(1)}}}),list:citty.defineCommand({meta:{name:"list",description:"List configured hooks"},async run(){await githooks$1.listHooks()}})}});exports.default=githooks;
@@ -1 +0,0 @@
1
- import{defineCommand as t}from"citty";import{consola as e}from"consola";import{l as a,u as s,i as c}from"../shared/basis.O4so-uuj.mjs";import"node:child_process";import"node:fs/promises";import"pathe";import"../shared/basis.C0E7mwQ6.mjs";import"c12";import"../config.mjs";const n=t({meta:{name:"hooks",description:"Manage git hooks"},subCommands:{install:t({meta:{name:"install",description:"Install git hooks"},args:{"auto-init-git":{type:"boolean",description:"Automatically initialize git repository if not found"},"skip-git-check":{type:"boolean",description:"Skip git command availability check"},force:{type:"boolean",alias:"f",description:"Force operation even if git is not available"}},async run({args:i}){try{let o;(i["auto-init-git"]!==void 0||i["skip-git-check"]!==void 0||i.force!==void 0)&&(o={},i["auto-init-git"]!==void 0&&(o.autoInitGit=!!i["auto-init-git"]),i["skip-git-check"]!==void 0&&(o.skipGitCheck=!!i["skip-git-check"]),i.force!==void 0&&(o.force=!!i.force)),await c(process.cwd(),o)}catch(o){e.error("Failed to install hooks:",o),process.exit(1)}}}),uninstall:t({meta:{name:"uninstall",description:"Uninstall git hooks"},args:{"skip-git-check":{type:"boolean",description:"Skip git command availability check"},force:{type:"boolean",alias:"f",description:"Force operation even if git is not available"}},async run({args:i}){try{let o;(i["skip-git-check"]!==void 0||i.force!==void 0)&&(o={},i["skip-git-check"]!==void 0&&(o.skipGitCheck=!!i["skip-git-check"]),i.force!==void 0&&(o.force=!!i.force)),await s(process.cwd(),o)}catch(o){e.error("Failed to uninstall hooks:",o),process.exit(1)}}}),list:t({meta:{name:"list",description:"List configured hooks"},async run(){await a()}})}});export{n as default};
@@ -1 +0,0 @@
1
- "use strict";const node_child_process=require("node:child_process"),consola=require("consola"),pkgTypes=require("pkg-types"),m=require("semver"),utils=require("./basis.CSSuyvpq.cjs");function _interopDefaultCompat(e){return e&&typeof e=="object"&&"default"in e?e.default:e}const m__default=_interopDefaultCompat(m);async function updatePackageVersion(e,o={}){const{config:u}=await utils.loadConfig({cwd:e}),n=u.version||{},c=await pkgTypes.readPackageJSON(e),t=c.version;if(!t)throw new Error("No version found in package.json");const s=o.version?m__default.valid(o.version)?o.version:(()=>{throw new Error(`Invalid version format: ${o.version}`)})():(()=>{if(!m__default.valid(t))throw new Error(`Invalid current version format: ${t}`);const r=o.preid||n.prereleaseId||"edge",a=o.major?"major":o.minor?"minor":o.prerelease?"prerelease":"patch",d=o.prerelease?m__default.inc(t,a,r):m__default.inc(t,a);if(!d)throw new Error("Failed to calculate new version");return d})();consola.consola.info(`Updating version: ${t} \u2192 ${s}`),await pkgTypes.writePackageJSON(e,{...c,version:s});const i={oldVersion:t,newVersion:s};if(n.autoCommit){const r=o.message||n.commitMessage?.replace("{version}",s)||`chore: release v${s}`;try{node_child_process.execSync("git add package.json",{cwd:e}),node_child_process.execSync(`git commit -m "${r}"`,{cwd:e}),consola.consola.success(`Committed version update: ${r}`)}catch(a){consola.consola.warn("Failed to commit changes:",a)}}if(n.autoTag){const r=`${n.tagPrefix||"v"}${s}`;try{node_child_process.execSync(`git tag ${r}`,{cwd:e}),consola.consola.success(`Created git tag: ${r}`),i.tagName=r}catch(a){consola.consola.warn("Failed to create git tag:",a)}}if(n.autoPush)try{node_child_process.execSync("git push",{cwd:e}),n.autoTag&&node_child_process.execSync("git push --tags",{cwd:e}),consola.consola.success("Pushed changes to remote")}catch(r){consola.consola.warn("Failed to push changes:",r)}return i}exports.updatePackageVersion=updatePackageVersion;
@@ -1 +0,0 @@
1
- import{loadConfig as o}from"c12";import{defaultConfig as f}from"../config.mjs";async function i(a={}){return await o({name:"basis",cwd:process.cwd(),...a,defaults:{...f,...a.defaults}})}export{i as l};
@@ -1 +0,0 @@
1
- import{execSync as c}from"node:child_process";import{consola as i}from"consola";import{readPackageJSON as p,writePackageJSON as l}from"pkg-types";import m from"semver";import{l as v}from"./basis.C0E7mwQ6.mjs";async function f(o,r={}){const{config:w}=await v({cwd:o}),t=w.version||{},g=await p(o),a=g.version;if(!a)throw new Error("No version found in package.json");const n=r.version?m.valid(r.version)?r.version:(()=>{throw new Error(`Invalid version format: ${r.version}`)})():(()=>{if(!m.valid(a))throw new Error(`Invalid current version format: ${a}`);const e=r.preid||t.prereleaseId||"edge",s=r.major?"major":r.minor?"minor":r.prerelease?"prerelease":"patch",u=r.prerelease?m.inc(a,s,e):m.inc(a,s);if(!u)throw new Error("Failed to calculate new version");return u})();i.info(`Updating version: ${a} \u2192 ${n}`),await l(o,{...g,version:n});const d={oldVersion:a,newVersion:n};if(t.autoCommit){const e=r.message||t.commitMessage?.replace("{version}",n)||`chore: release v${n}`;try{c("git add package.json",{cwd:o}),c(`git commit -m "${e}"`,{cwd:o}),i.success(`Committed version update: ${e}`)}catch(s){i.warn("Failed to commit changes:",s)}}if(t.autoTag){const e=`${t.tagPrefix||"v"}${n}`;try{c(`git tag ${e}`,{cwd:o}),i.success(`Created git tag: ${e}`),d.tagName=e}catch(s){i.warn("Failed to create git tag:",s)}}if(t.autoPush)try{c("git push",{cwd:o}),t.autoTag&&c("git push --tags",{cwd:o}),i.success("Pushed changes to remote")}catch(e){i.warn("Failed to push changes:",e)}return d}export{f as u};
@@ -1,19 +0,0 @@
1
- import{existsSync as c,writeFileSync as m}from"node:fs";import{consola as e}from"consola";import{detectPackageManager as u,addDevDependency as g,installDependencies as k}from"nypm";import{resolve as n}from"pathe";import{readPackageJSON as w,writePackageJSON as y}from"pkg-types";const b=`import { defineBasisConfig } from "@funish/basis";
2
-
3
- export default defineBasisConfig({
4
- lint: {
5
- staged: {
6
- },
7
- commitMsg: {
8
- // types: ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert"],
9
- // maxLength: 72,
10
- // minLength: 10,
11
- },
12
- },
13
-
14
- hooks: {
15
- // "pre-commit": "basis lint --staged",
16
- // "commit-msg": "basis lint --commit-msg",
17
- },
18
- });
19
- `;async function h(t=process.cwd(),p={}){const{force:l=!1,skipGitCheck:d=!1,skipInstall:a=!1}=p;e.start("Initializing basis configuration...");const r=n(t,"basis.config.ts");if(c(r)&&!l)return e.error("basis.config.ts already exists. Use --force to overwrite."),!1;if(!d&&!c(n(t,".git"))&&(e.warn("No .git directory found. Git hooks will not work properly."),!await e.prompt("Continue anyway?",{type:"confirm",initial:!1})))return e.info("Initialization cancelled."),!1;const o=(await u(t))?.name||"npm";e.info(`Detected package manager: ${o}`),m(r,b,"utf-8"),e.success("Created basis.config.ts");try{const s=await w(t),f=!!(s.workspaces||c(n(t,"pnpm-workspace.yaml")));a?!s.devDependencies?.["@funish/basis"]&&!s.dependencies?.["@funish/basis"]&&(s.devDependencies=s.devDependencies||{},s.devDependencies["@funish/basis"]="latest",e.info("Added @funish/basis to devDependencies")):(await g("@funish/basis",{cwd:t,silent:!1,workspace:f}),e.success("Added @funish/basis to devDependencies"));const i="basis hooks install";s.scripts=s.scripts||{},o==="pnpm"?s.scripts.postinstall?s.scripts.postinstall.includes(i)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${i}`):s.scripts.postinstall=i:o==="yarn"?s.scripts.prepare?s.scripts.prepare.includes(i)||(s.scripts.prepare=`${s.scripts.prepare} && ${i}`):s.scripts.prepare=i:s.scripts.postinstall?s.scripts.postinstall.includes(i)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${i}`):s.scripts.postinstall=i,await y(n(t,"package.json"),s),e.success(`Updated package.json scripts${a?" and dependencies":""}`),a?(e.info("Skipped dependency installation"),e.info("Run your package manager's install command to complete setup")):(e.start("Installing dependencies..."),await k({cwd:t,silent:!1}),e.success("Dependencies installed successfully"))}catch(s){return e.error("Failed to setup dependencies:",s),!1}return e.success("Basis initialization completed!"),e.info("You can now:"),e.info(" - Edit basis.config.ts to customize your configuration"),e.info(" - Run `basis hooks install` to install git hooks"),!0}export{h as i};
@@ -1 +0,0 @@
1
- "use strict";const c12=require("c12"),config=require("../config.cjs");async function loadConfig(c={}){return await c12.loadConfig({name:"basis",cwd:process.cwd(),...c,defaults:{...config.defaultConfig,...c.defaults}})}exports.loadConfig=loadConfig;
@@ -1,4 +0,0 @@
1
- "use strict";const node_child_process=require("node:child_process"),node_fs=require("node:fs"),consola=require("consola"),y=require("micromatch"),pathe=require("pathe"),utils=require("./basis.CSSuyvpq.cjs");function _interopDefaultCompat(e){return e&&typeof e=="object"&&"default"in e?e.default:e}const y__default=_interopDefaultCompat(y),M=["feat","fix","docs","style","refactor","perf","test","build","ci","chore","revert"];function parseCommitMessage(e){const i=e.trim().split(`
2
- `),t=i[0].match(/^(\w+)(\(([^)]+)\))?(!)?:\s*(.+)$/);if(!t)return null;const[,l,,n,c,o]=t,a=i.slice(1).find(s=>s.trim())?.trim(),r=i.slice(-1)[0]?.trim();return{type:l,scope:n,description:o,body:a,footer:r,isBreaking:!!c||e.includes("BREAKING CHANGE:")}}function validateCommitMessage(e,i={}){const t=[],{types:l=M,maxLength:n=72,minLength:c=10,scopeRequired:o=!1,allowedScopes:a=[]}=i,r=parseCommitMessage(e);if(!r)return{valid:!1,errors:["Invalid commit format. Expected: type(scope): description"]};l.includes(r.type)||t.push(`Invalid type '${r.type}'. Allowed: ${l.join(", ")}`);const s=e.split(`
3
- `)[0];return s.length>n&&t.push(`Header too long (${s.length}). Max: ${n}`),s.length<c&&t.push(`Header too short (${s.length}). Min: ${c}`),o&&!r.scope&&t.push("Scope is required"),r.scope&&a.length>0&&!a.includes(r.scope)&&t.push(`Invalid scope '${r.scope}'. Allowed: ${a.join(", ")}`),{valid:t.length===0,errors:t}}function getStagedFiles(){try{return node_child_process.execSync("git diff --cached --name-only",{encoding:"utf8"}).trim().split(`
4
- `).filter(Boolean)}catch{return[]}}async function lintStaged(e=process.cwd(),i){const{config:t}=await utils.loadConfig({cwd:e,overrides:i?{lint:{staged:i}}:void 0}),l=t.lint?.staged||{},n=getStagedFiles();if(n.length===0)return consola.consola.info("No staged files to lint"),!0;if(Object.keys(l).length===0)return consola.consola.warn("No staged lint configuration found"),!0;let c=!1;const o=new Set;for(const[a,r]of Object.entries(l)){const s=n.filter(d=>!o.has(d)&&y__default.isMatch(d.split("/").pop()||d,a));if(s.length!==0){consola.consola.start(`Linting ${s.length} files: ${a}`);try{const d=`${r} ${s.join(" ")}`;node_child_process.execSync(d,{stdio:"inherit",cwd:e}),node_child_process.execSync(`git add ${s.join(" ")}`,{stdio:"inherit",cwd:e}),s.forEach(u=>o.add(u)),consola.consola.success(`\u2713 ${a}`)}catch(d){c=!0,consola.consola.error(`\u2717 ${a} failed:`,d)}}}return!c}async function lintCommitMessage(e=process.cwd(),i){const{config:t}=await utils.loadConfig({cwd:e,overrides:i?{lint:{commitMsg:i}}:void 0}),l=t.lint?.commitMsg||{};let n;try{const o=pathe.resolve(".git/COMMIT_EDITMSG");node_fs.existsSync(o)?n=node_fs.readFileSync(o,"utf8"):n=node_child_process.execSync("git log -1 --pretty=%B",{encoding:"utf8"}).trim()}catch(o){return consola.consola.error("\u2717 Failed to read commit message:",o),!1}const c=validateCommitMessage(n,l);return c.valid?(consola.consola.success("\u2713 Commit message is valid"),!0):(consola.consola.error("\u2717 Invalid commit message:"),c.errors.forEach(o=>consola.consola.error(` ${o}`)),!1)}exports.getStagedFiles=getStagedFiles,exports.lintCommitMessage=lintCommitMessage,exports.lintStaged=lintStaged,exports.parseCommitMessage=parseCommitMessage,exports.validateCommitMessage=validateCommitMessage;
@@ -1,5 +0,0 @@
1
- "use strict";const node_child_process=require("node:child_process"),promises=require("node:fs/promises"),consola=require("consola"),pathe=require("pathe"),utils=require("./basis.CSSuyvpq.cjs"),VALID_GIT_HOOKS=["applypatch-msg","pre-applypatch","post-applypatch","pre-commit","pre-merge-commit","prepare-commit-msg","commit-msg","post-commit","pre-rebase","post-checkout","post-merge","pre-push","pre-receive","update","proc-receive","post-receive","post-update","reference-transaction","push-to-checkout","pre-auto-gc","post-rewrite","sendemail-validate","fsmonitor-watchman","p4-changelist","p4-prepare-changelist","p4-post-changelist","p4-pre-submit","post-index-change"];async function y(){try{return node_child_process.execSync("git --version",{stdio:"ignore"}),!0}catch{return!1}}async function b(o){try{return await promises.access(pathe.join(o,".git")),!0}catch{return!1}}async function j(o){try{node_child_process.execSync("git init",{cwd:o,stdio:"inherit"}),consola.consola.success("Initialized git repository")}catch(i){throw consola.consola.error("Failed to initialize git repository:",i),i}}function w(o){return VALID_GIT_HOOKS.includes(o)}function u(o){const i={},r={autoInitGit:o.autoInitGit,skipGitCheck:o.skipGitCheck,force:o.force};for(const[e,n]of Object.entries(o))e!=="autoInitGit"&&e!=="skipGitCheck"&&e!=="force"&&typeof n=="string"&&(i[e]=n);return{hooks:i,options:r}}function p(o){const i=[];for(const r of Object.keys(o))w(r)||i.push(r);return{valid:i.length===0,invalidHooks:i}}async function installHooks(o=process.cwd(),i){const{config:r}=await utils.loadConfig({cwd:o,overrides:i?{githooks:i}:void 0}),e=r.githooks;if(!e){consola.consola.error("No hooks configuration found");return}const{hooks:n,options:s}=u(e);if(!s.skipGitCheck&&!s.force&&!await y())throw consola.consola.error("Git command not found. Please install git or use --force option."),new Error("Git command not available");if(!await b(o))if(s.autoInitGit)consola.consola.info("Not a git repository, initializing..."),await j(o);else throw consola.consola.error("Not a git repository. Use --auto-init-git option or run 'git init' first."),new Error("Not a git repository");const a=p(n);if(!a.valid)throw consola.consola.error("Invalid hook names found:"),a.invalidHooks.forEach(t=>{consola.consola.error(` \u2717 ${t} (not a valid Git hook)`)}),consola.consola.info("Valid Git hooks:",VALID_GIT_HOOKS.join(", ")),new Error(`Invalid hook names: ${a.invalidHooks.join(", ")}`);if(consola.consola.start("Installing git hooks..."),Object.keys(n).length===0){consola.consola.warn("No hooks configured");return}try{const t=pathe.join(o,".git","hooks");await promises.mkdir(t,{recursive:!0});for(const[c,l]of Object.entries(n)){const h=pathe.join(t,c),f=O(l);await promises.writeFile(h,f,"utf-8"),await promises.chmod(h,493),consola.consola.info(`Installed ${c} hook`)}consola.consola.success(`Installed ${Object.keys(n).length} git hooks`)}catch(t){throw consola.consola.error("Failed to install hooks:",t),t}}async function uninstallHooks(o=process.cwd(),i){const{config:r}=await utils.loadConfig({cwd:o,overrides:i?{githooks:i}:void 0}),e=r.githooks||{},{hooks:n,options:s}=u(e);if(!s.skipGitCheck&&!s.force&&!await y())throw consola.consola.error("Git command not found. Please install git or use --force option."),new Error("Git command not available");if(!await b(o)&&!s.force)throw consola.consola.error("Not a git repository."),new Error("Not a git repository");const a=p(n);if(!a.valid)throw consola.consola.error("Invalid hook names found:"),a.invalidHooks.forEach(t=>{consola.consola.error(` \u2717 ${t} (not a valid Git hook)`)}),new Error(`Invalid hook names: ${a.invalidHooks.join(", ")}`);consola.consola.start("Uninstalling git hooks...");try{const t=pathe.join(o,".git","hooks");for(const c of Object.keys(n)){const l=pathe.join(t,c);try{await promises.writeFile(l,"","utf-8"),consola.consola.info(`Uninstalled ${c} hook`)}catch{}}consola.consola.success("Git hooks uninstalled")}catch(t){throw consola.consola.error("Failed to uninstall hooks:",t),t}}async function listHooks(o=process.cwd(),i){const{config:r}=await utils.loadConfig({cwd:o,overrides:i?{githooks:i}:void 0}),e=r.githooks||{},{hooks:n,options:s}=u(e);if(consola.consola.info("Configured git hooks:"),Object.keys(n).length===0){consola.consola.info("No hooks configured");return}(s.autoInitGit||s.skipGitCheck||s.force)&&(consola.consola.info("Options:"),s.autoInitGit&&consola.consola.info(" \u2022 Auto-init git: enabled"),s.skipGitCheck&&consola.consola.info(" \u2022 Skip git check: enabled"),s.force&&consola.consola.info(" \u2022 Force: enabled"));const a=p(n);a.valid||(consola.consola.warn("Warning: Found invalid hook names:"),a.invalidHooks.forEach(t=>{consola.consola.warn(` \u26A0 ${t} (not a valid Git hook)`)}));for(const[t,c]of Object.entries(n)){const l=w(t)?"\u2713":"\u26A0";consola.consola.info(` ${l} ${t}: ${c}`)}}function O(o){return`#!/bin/sh
2
- # Generated by @funish/basis
3
-
4
- ${o}
5
- `}exports.VALID_GIT_HOOKS=VALID_GIT_HOOKS,exports.installHooks=installHooks,exports.listHooks=listHooks,exports.uninstallHooks=uninstallHooks;
@@ -1,19 +0,0 @@
1
- "use strict";const node_fs=require("node:fs"),consola=require("consola"),nypm=require("nypm"),pathe=require("pathe"),pkgTypes=require("pkg-types"),b=`import { defineBasisConfig } from "@funish/basis";
2
-
3
- export default defineBasisConfig({
4
- lint: {
5
- staged: {
6
- },
7
- commitMsg: {
8
- // types: ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert"],
9
- // maxLength: 72,
10
- // minLength: 10,
11
- },
12
- },
13
-
14
- hooks: {
15
- // "pre-commit": "basis lint --staged",
16
- // "commit-msg": "basis lint --commit-msg",
17
- },
18
- });
19
- `;async function init(i=process.cwd(),a={}){const{force:c=!1,skipGitCheck:r=!1,skipInstall:n=!1}=a;consola.consola.start("Initializing basis configuration...");const o=pathe.resolve(i,"basis.config.ts");if(node_fs.existsSync(o)&&!c)return consola.consola.error("basis.config.ts already exists. Use --force to overwrite."),!1;if(!r&&!node_fs.existsSync(pathe.resolve(i,".git"))&&(consola.consola.warn("No .git directory found. Git hooks will not work properly."),!await consola.consola.prompt("Continue anyway?",{type:"confirm",initial:!1})))return consola.consola.info("Initialization cancelled."),!1;const t=(await nypm.detectPackageManager(i))?.name||"npm";consola.consola.info(`Detected package manager: ${t}`),node_fs.writeFileSync(o,b,"utf-8"),consola.consola.success("Created basis.config.ts");try{const s=await pkgTypes.readPackageJSON(i),l=!!(s.workspaces||node_fs.existsSync(pathe.resolve(i,"pnpm-workspace.yaml")));n?!s.devDependencies?.["@funish/basis"]&&!s.dependencies?.["@funish/basis"]&&(s.devDependencies=s.devDependencies||{},s.devDependencies["@funish/basis"]="latest",consola.consola.info("Added @funish/basis to devDependencies")):(await nypm.addDevDependency("@funish/basis",{cwd:i,silent:!1,workspace:l}),consola.consola.success("Added @funish/basis to devDependencies"));const e="basis hooks install";s.scripts=s.scripts||{},t==="pnpm"?s.scripts.postinstall?s.scripts.postinstall.includes(e)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${e}`):s.scripts.postinstall=e:t==="yarn"?s.scripts.prepare?s.scripts.prepare.includes(e)||(s.scripts.prepare=`${s.scripts.prepare} && ${e}`):s.scripts.prepare=e:s.scripts.postinstall?s.scripts.postinstall.includes(e)||(s.scripts.postinstall=`${s.scripts.postinstall} && ${e}`):s.scripts.postinstall=e,await pkgTypes.writePackageJSON(pathe.resolve(i,"package.json"),s),consola.consola.success(`Updated package.json scripts${n?" and dependencies":""}`),n?(consola.consola.info("Skipped dependency installation"),consola.consola.info("Run your package manager's install command to complete setup")):(consola.consola.start("Installing dependencies..."),await nypm.installDependencies({cwd:i,silent:!1}),consola.consola.success("Dependencies installed successfully"))}catch(s){return consola.consola.error("Failed to setup dependencies:",s),!1}return consola.consola.success("Basis initialization completed!"),consola.consola.info("You can now:"),consola.consola.info(" - Edit basis.config.ts to customize your configuration"),consola.consola.info(" - Run `basis hooks install` to install git hooks"),!0}exports.init=init;
@@ -1,5 +0,0 @@
1
- import{execSync as m}from"node:child_process";import{writeFile as w,mkdir as I,chmod as j,access as O}from"node:fs/promises";import{consola as o}from"consola";import{join as h}from"pathe";import{l as p}from"./basis.C0E7mwQ6.mjs";const u=["applypatch-msg","pre-applypatch","post-applypatch","pre-commit","pre-merge-commit","prepare-commit-msg","commit-msg","post-commit","pre-rebase","post-checkout","post-merge","pre-push","pre-receive","update","proc-receive","post-receive","post-update","reference-transaction","push-to-checkout","pre-auto-gc","post-rewrite","sendemail-validate","fsmonitor-watchman","p4-changelist","p4-prepare-changelist","p4-post-changelist","p4-pre-submit","post-index-change"];async function v(){try{return m("git --version",{stdio:"ignore"}),!0}catch{return!1}}async function y(t){try{return await O(h(t,".git")),!0}catch{return!1}}async function $(t){try{m("git init",{cwd:t,stdio:"inherit"}),o.success("Initialized git repository")}catch(n){throw o.error("Failed to initialize git repository:",n),n}}function G(t){return u.includes(t)}function d(t){const n={},a={autoInitGit:t.autoInitGit,skipGitCheck:t.skipGitCheck,force:t.force};for(const[s,r]of Object.entries(t))s!=="autoInitGit"&&s!=="skipGitCheck"&&s!=="force"&&typeof r=="string"&&(n[s]=r);return{hooks:n,options:a}}function k(t){const n=[];for(const a of Object.keys(t))G(a)||n.push(a);return{valid:n.length===0,invalidHooks:n}}async function H(t=process.cwd(),n){const{config:a}=await p({cwd:t,overrides:n?{githooks:n}:void 0}),s=a.githooks;if(!s){o.error("No hooks configuration found");return}const{hooks:r,options:e}=d(s);if(!e.skipGitCheck&&!e.force&&!await v())throw o.error("Git command not found. Please install git or use --force option."),new Error("Git command not available");if(!await y(t))if(e.autoInitGit)o.info("Not a git repository, initializing..."),await $(t);else throw o.error("Not a git repository. Use --auto-init-git option or run 'git init' first."),new Error("Not a git repository");const c=k(r);if(!c.valid)throw o.error("Invalid hook names found:"),c.invalidHooks.forEach(i=>{o.error(` \u2717 ${i} (not a valid Git hook)`)}),o.info("Valid Git hooks:",u.join(", ")),new Error(`Invalid hook names: ${c.invalidHooks.join(", ")}`);if(o.start("Installing git hooks..."),Object.keys(r).length===0){o.warn("No hooks configured");return}try{const i=h(t,".git","hooks");await I(i,{recursive:!0});for(const[f,l]of Object.entries(r)){const g=h(i,f),b=N(l);await w(g,b,"utf-8"),await j(g,493),o.info(`Installed ${f} hook`)}o.success(`Installed ${Object.keys(r).length} git hooks`)}catch(i){throw o.error("Failed to install hooks:",i),i}}async function C(t=process.cwd(),n){const{config:a}=await p({cwd:t,overrides:n?{githooks:n}:void 0}),s=a.githooks||{},{hooks:r,options:e}=d(s);if(!e.skipGitCheck&&!e.force&&!await v())throw o.error("Git command not found. Please install git or use --force option."),new Error("Git command not available");if(!await y(t)&&!e.force)throw o.error("Not a git repository."),new Error("Not a git repository");const c=k(r);if(!c.valid)throw o.error("Invalid hook names found:"),c.invalidHooks.forEach(i=>{o.error(` \u2717 ${i} (not a valid Git hook)`)}),new Error(`Invalid hook names: ${c.invalidHooks.join(", ")}`);o.start("Uninstalling git hooks...");try{const i=h(t,".git","hooks");for(const f of Object.keys(r)){const l=h(i,f);try{await w(l,"","utf-8"),o.info(`Uninstalled ${f} hook`)}catch{}}o.success("Git hooks uninstalled")}catch(i){throw o.error("Failed to uninstall hooks:",i),i}}async function E(t=process.cwd(),n){const{config:a}=await p({cwd:t,overrides:n?{githooks:n}:void 0}),s=a.githooks||{},{hooks:r,options:e}=d(s);if(o.info("Configured git hooks:"),Object.keys(r).length===0){o.info("No hooks configured");return}(e.autoInitGit||e.skipGitCheck||e.force)&&(o.info("Options:"),e.autoInitGit&&o.info(" \u2022 Auto-init git: enabled"),e.skipGitCheck&&o.info(" \u2022 Skip git check: enabled"),e.force&&o.info(" \u2022 Force: enabled"));const c=k(r);c.valid||(o.warn("Warning: Found invalid hook names:"),c.invalidHooks.forEach(i=>{o.warn(` \u26A0 ${i} (not a valid Git hook)`)}));for(const[i,f]of Object.entries(r)){const l=G(i)?"\u2713":"\u26A0";o.info(` ${l} ${i}: ${f}`)}}function N(t){return`#!/bin/sh
2
- # Generated by @funish/basis
3
-
4
- ${t}
5
- `}export{u as V,H as i,E as l,C as u};