fg-devkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor/rules/core-coding-standards.mdc +203 -0
- package/LICENSE +19 -0
- package/README.md +13 -0
- package/configs/dependency-policy.vue-workspace.json +116 -0
- package/configs/eslint.config.base.js +262 -0
- package/configs/eslint.sync-stub.js +19 -0
- package/configs/prettier.config.js +16 -0
- package/configs/tsconfig.app.sync.json +38 -0
- package/configs/tsconfig.base.json +18 -0
- package/configs/vscode-settings.json +74 -0
- package/package.json +67 -0
- package/scripts/check-dependency-policy.mjs +135 -0
- package/scripts/cz/.cz-config.cjs +26 -0
- package/scripts/cz/cz-adapter.cjs +116 -0
- package/scripts/dependency-policy-pins.mjs +35 -0
- package/scripts/fg-devkit.mjs +247 -0
- package/scripts/refresh-dependency-policy-from-repos.mjs +191 -0
- package/scripts/release.sh +72 -0
- package/scripts/resolve-dependency-policy-path.mjs +32 -0
- package/scripts/sync-dependency-policy.mjs +123 -0
- package/scripts/sync-peers-from-dev.mjs +31 -0
- package/scripts/sync-project-configs.mjs +32 -0
- package/scripts/sync-tooling-configs.mjs +62 -0
- package/scripts/sync-vscode-settings.mjs +39 -0
- package/scripts/vuln-commit.mjs +142 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Runs all local DX config sync steps: VS Code settings, then Prettier / ESLint / tsconfig (see sync-tooling-configs.mjs).
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node node_modules/fg-devkit/scripts/sync-project-configs.mjs
|
|
7
|
+
* pnpm exec fg-devkit sync-project-configs
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { spawnSync } from 'node:child_process'
|
|
11
|
+
import path from 'node:path'
|
|
12
|
+
import { fileURLToPath } from 'node:url'
|
|
13
|
+
|
|
14
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url))
|
|
15
|
+
|
|
16
|
+
function runScript(name) {
|
|
17
|
+
const r = spawnSync(process.execPath, [path.join(scriptDir, name)], {
|
|
18
|
+
stdio: 'inherit',
|
|
19
|
+
cwd: process.cwd(),
|
|
20
|
+
env: process.env,
|
|
21
|
+
})
|
|
22
|
+
if (r.error) {
|
|
23
|
+
console.error('[sync-project]', r.error.message)
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
if (r.status !== 0 && r.status !== null) {
|
|
27
|
+
process.exit(r.status)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
runScript('sync-vscode-settings.mjs')
|
|
32
|
+
runScript('sync-tooling-configs.mjs')
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Syncs shared tooling files from fg-devkit into the repo root:
|
|
4
|
+
* - prettier.config.js — full copy from fg-devkit
|
|
5
|
+
* - eslint.config.js — copy of the minimal eslint.sync-stub.js (flat config + createBaseConfig)
|
|
6
|
+
* - tsconfig.json — full copy of tsconfig.app.sync.json (Vue app defaults: include/exclude,
|
|
7
|
+
* compilerOptions, vueCompilerOptions, extends fg-devkit/tsconfig.base.json)
|
|
8
|
+
*
|
|
9
|
+
* Requires fg-devkit on disk (direct dependency or via fds-vue-core).
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* node node_modules/fg-devkit/scripts/sync-tooling-configs.mjs
|
|
13
|
+
* pnpm exec fg-devkit sync-tooling-configs
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs'
|
|
17
|
+
import path from 'node:path'
|
|
18
|
+
|
|
19
|
+
const projectRoot = process.cwd()
|
|
20
|
+
|
|
21
|
+
function findFgDevkitPackageRoot() {
|
|
22
|
+
const candidates = [
|
|
23
|
+
path.join(projectRoot, 'node_modules', 'fg-devkit'),
|
|
24
|
+
path.join(projectRoot, 'node_modules', 'fds-vue-core', 'node_modules', 'fg-devkit'),
|
|
25
|
+
]
|
|
26
|
+
for (const p of candidates) {
|
|
27
|
+
if (fs.existsSync(path.join(p, 'package.json'))) {
|
|
28
|
+
return p
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const fgRoot = findFgDevkitPackageRoot()
|
|
35
|
+
if (!fgRoot) {
|
|
36
|
+
console.error(
|
|
37
|
+
'[sync-tooling] Could not find fg-devkit (install fg-devkit or a package that bundles it, e.g. fds-vue-core).',
|
|
38
|
+
)
|
|
39
|
+
process.exit(1)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const prettierSrc = path.join(fgRoot, 'configs', 'prettier.config.js')
|
|
43
|
+
const eslintStubSrc = path.join(fgRoot, 'configs', 'eslint.sync-stub.js')
|
|
44
|
+
const tsconfigSrc = path.join(fgRoot, 'configs', 'tsconfig.app.sync.json')
|
|
45
|
+
|
|
46
|
+
if (!fs.existsSync(prettierSrc) || !fs.existsSync(eslintStubSrc) || !fs.existsSync(tsconfigSrc)) {
|
|
47
|
+
console.error(
|
|
48
|
+
'[sync-tooling] Missing prettier.config.js, eslint.sync-stub.js, or tsconfig.app.sync.json inside fg-devkit package.',
|
|
49
|
+
)
|
|
50
|
+
process.exit(1)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
fs.copyFileSync(prettierSrc, path.join(projectRoot, 'prettier.config.js'))
|
|
55
|
+
fs.copyFileSync(eslintStubSrc, path.join(projectRoot, 'eslint.config.js'))
|
|
56
|
+
fs.copyFileSync(tsconfigSrc, path.join(projectRoot, 'tsconfig.json'))
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error(`[sync-tooling] ${err.message}`)
|
|
59
|
+
process.exit(1)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
console.log('[sync-tooling] Updated prettier.config.js, eslint.config.js, and tsconfig.json.')
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copies the shared VS Code settings file from fg-devkit (or a fallback) into the repo’s
|
|
5
|
+
* .vscode/settings.json so editors pick up team defaults after install.
|
|
6
|
+
*
|
|
7
|
+
* If no template is found (e.g. fg-devkit not installed), exits 0 without error.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node node_modules/fg-devkit/scripts/sync-vscode-settings.mjs
|
|
11
|
+
* # or add an npm script that runs this file
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { copyFileSync, existsSync, mkdirSync } from 'fs'
|
|
15
|
+
import { dirname, join } from 'path'
|
|
16
|
+
|
|
17
|
+
const projectRoot = process.cwd()
|
|
18
|
+
|
|
19
|
+
/** Search order: linked fg-devkit, legacy fds-vue-core path, or local configs/ in the repo. */
|
|
20
|
+
const candidates = [
|
|
21
|
+
join(projectRoot, 'node_modules', 'fg-devkit', 'configs', 'vscode-settings.json'),
|
|
22
|
+
join(projectRoot, 'node_modules', 'fds-vue-core', 'configs', 'vscode-settings.json'),
|
|
23
|
+
join(projectRoot, 'configs', 'vscode-settings.json'),
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
const baseSettingsPath = candidates.find((p) => existsSync(p)) ?? null
|
|
27
|
+
const localSettingsPath = join(projectRoot, '.vscode', 'settings.json')
|
|
28
|
+
|
|
29
|
+
if (!baseSettingsPath) {
|
|
30
|
+
process.exit(0)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
mkdirSync(dirname(localSettingsPath), { recursive: true })
|
|
35
|
+
copyFileSync(baseSettingsPath, localSettingsPath)
|
|
36
|
+
} catch (error) {
|
|
37
|
+
console.error('Error syncing VS Code settings:', error.message)
|
|
38
|
+
process.exit(1)
|
|
39
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Git helper for security bumps: inspects staged package.json files, detects dependency
|
|
5
|
+
* version changes vs HEAD, and creates a conventional commit with a vuln() message.
|
|
6
|
+
*
|
|
7
|
+
* Intended for use as a bin (fg-vuln-commit / fds-vuln-commit) or from a git hook after
|
|
8
|
+
* staging lockfile/package.json changes. Requires a clean git invocation with staged changes.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
|
|
13
|
+
/** Run a shell command and return stdout, or empty string on failure. */
|
|
14
|
+
function run(command) {
|
|
15
|
+
try {
|
|
16
|
+
return execSync(command, { encoding: "utf8" }).trim();
|
|
17
|
+
} catch {
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Run a shell command; throws on non-zero exit (stdio inherited). */
|
|
23
|
+
function runOrThrow(command) {
|
|
24
|
+
return execSync(command, { encoding: "utf8", stdio: "inherit" });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function out(text = "") {
|
|
28
|
+
process.stdout.write(`${text}\n`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Load JSON from a git object path (e.g. HEAD:package.json or :path for index). */
|
|
32
|
+
function parseJsonAtRef(refPath) {
|
|
33
|
+
const raw = run(`git show ${refPath}`);
|
|
34
|
+
if (!raw) return null;
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(raw);
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readStagedFile(path) {
|
|
43
|
+
return parseJsonAtRef(`:${path}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function readHeadFile(path) {
|
|
47
|
+
return parseJsonAtRef(`HEAD:${path}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Flatten all version-bearing sections from a package.json for diffing. */
|
|
51
|
+
function collectDeps(pkgJson) {
|
|
52
|
+
if (!pkgJson) return {};
|
|
53
|
+
return {
|
|
54
|
+
...(pkgJson.dependencies || {}),
|
|
55
|
+
...(pkgJson.devDependencies || {}),
|
|
56
|
+
...(pkgJson.peerDependencies || {}),
|
|
57
|
+
...(pkgJson.optionalDependencies || {}),
|
|
58
|
+
...(pkgJson.overrides || {}),
|
|
59
|
+
...((pkgJson.pnpm && pkgJson.pnpm.overrides) || {}),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function normalize(version) {
|
|
64
|
+
if (typeof version !== "string") return version;
|
|
65
|
+
return version.trim();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function semverFrom(value) {
|
|
69
|
+
if (typeof value !== "string") return null;
|
|
70
|
+
const match = value.match(/(\d+\.\d+\.\d+)/);
|
|
71
|
+
return match ? match[1] : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Entry: diff staged package.json files against HEAD, then commit with a vuln-prefixed message. */
|
|
75
|
+
function main() {
|
|
76
|
+
const stagedFiles = run("git diff --cached --name-only")
|
|
77
|
+
.split("\n")
|
|
78
|
+
.map((s) => s.trim())
|
|
79
|
+
.filter(Boolean);
|
|
80
|
+
|
|
81
|
+
const packageJsonPaths = stagedFiles.filter((p) => p.endsWith("package.json"));
|
|
82
|
+
if (packageJsonPaths.length === 0) {
|
|
83
|
+
out("No staged package.json changes found.");
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const updates = [];
|
|
88
|
+
|
|
89
|
+
for (const path of packageJsonPaths) {
|
|
90
|
+
const stagedPkg = readStagedFile(path);
|
|
91
|
+
const headPkg = readHeadFile(path) || {};
|
|
92
|
+
if (!stagedPkg) continue;
|
|
93
|
+
|
|
94
|
+
const before = collectDeps(headPkg);
|
|
95
|
+
const after = collectDeps(stagedPkg);
|
|
96
|
+
const keys = new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
97
|
+
|
|
98
|
+
for (const name of keys) {
|
|
99
|
+
const oldV = normalize(before[name]);
|
|
100
|
+
const newV = normalize(after[name]);
|
|
101
|
+
if (oldV && newV && oldV !== newV) {
|
|
102
|
+
updates.push({ name, from: oldV, to: newV, path });
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (updates.length === 0) {
|
|
108
|
+
out("No staged dependency version changes found in package.json.");
|
|
109
|
+
process.exit(0);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
out("Detected staged dependency updates:\n");
|
|
113
|
+
for (const u of updates) {
|
|
114
|
+
out(`- ${u.name}: ${u.from} -> ${u.to} (${u.path})`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const commitMessage =
|
|
118
|
+
updates.length === 1
|
|
119
|
+
? `vuln(${updates[0].name}@${semverFrom(updates[0].from) || updates[0].from}): bump to ${semverFrom(updates[0].to) || updates[0].to}`
|
|
120
|
+
: "vuln(): updated dependencies";
|
|
121
|
+
const commitBody =
|
|
122
|
+
updates.length > 1
|
|
123
|
+
? `updated dependencies\n${updates.map((u) => `- ${u.name}: ${u.from} -> ${u.to}`).join("\n")}`
|
|
124
|
+
: "";
|
|
125
|
+
|
|
126
|
+
const hasStagedChanges = run("git diff --cached --name-only");
|
|
127
|
+
if (!hasStagedChanges) {
|
|
128
|
+
out("\nNo staged changes to commit.");
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const escapedMessage = commitMessage.replace(/"/g, '\\"');
|
|
133
|
+
const escapedBody = commitBody.replace(/"/g, '\\"');
|
|
134
|
+
const commitCommand = commitBody
|
|
135
|
+
? `git commit -m "${escapedMessage}" -m "${escapedBody}"`
|
|
136
|
+
: `git commit -m "${escapedMessage}"`;
|
|
137
|
+
|
|
138
|
+
out(`\nCreating commit:\n${commitMessage}\n`);
|
|
139
|
+
runOrThrow(commitCommand);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
main();
|