monecromanci 0.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/README.md +84 -0
- package/dist/assets/azure-pipelines.yml +33 -0
- package/dist/assets/build-templates/01-preparation.mjs +174 -0
- package/dist/assets/build-templates/01-preparation.yml +51 -0
- package/dist/assets/build-templates/02-quality-control.mjs +32 -0
- package/dist/assets/build-templates/02-quality-control.yml +24 -0
- package/dist/assets/build-templates/03-package-apps.mjs +573 -0
- package/dist/assets/build-templates/03-package-apps.yml +37 -0
- package/dist/assets/build-templates/04-publish-libs.mjs +155 -0
- package/dist/assets/build-templates/04-publish-libs.yml +20 -0
- package/dist/assets/build-templates/05-publish-documentation.mjs +88 -0
- package/dist/assets/build-templates/05-publish-documentation.yml +20 -0
- package/dist/assets/build-templates/06-summary.mjs +463 -0
- package/dist/assets/build-templates/06-summary.yml +4 -0
- package/dist/assets/build-templates/README.md +69 -0
- package/dist/assets/build-templates/lib/_h.mjs +299 -0
- package/dist/assets/build-templates/lib/context.mjs +359 -0
- package/dist/assets/build-templates/lib/nx.mjs +254 -0
- package/dist/assets/eslint.config.mjs +306 -0
- package/dist/assets/github/workflows/ci.yml +67 -0
- package/dist/assets/scripts/clean-config.mjs +35 -0
- package/dist/assets/scripts/generate-dist-package.mjs +205 -0
- package/dist/assets/scripts/next-build.mjs +37 -0
- package/dist/cli.js +2466 -0
- package/dist/cli.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates `dist/package.json` for a publishable library or CLI tool.
|
|
5
|
+
*
|
|
6
|
+
* Because every dependency lives in the monorepo ROOT package.json, a project's
|
|
7
|
+
* own package.json declares no runtime deps. This script fixes the classic
|
|
8
|
+
* "published a package with no dependencies" problem: it scans the built output
|
|
9
|
+
* for the packages actually imported, resolves their versions from the root
|
|
10
|
+
* manifest (and internal workspace packages from their own package.json), and
|
|
11
|
+
* writes a correct, publishable `dist/package.json`.
|
|
12
|
+
*
|
|
13
|
+
* Run from a project directory (cwd = project root) after the build emits dist:
|
|
14
|
+
* tsc -p ./tsconfig.lib.json && node ../../tools/generate-dist-package.mjs
|
|
15
|
+
*
|
|
16
|
+
* Dist field overrides (main/types/bin) come from `monecromanci.dist` in the
|
|
17
|
+
* project package.json.
|
|
18
|
+
*/
|
|
19
|
+
import { builtinModules } from 'node:module'
|
|
20
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'
|
|
21
|
+
import { join, resolve } from 'node:path'
|
|
22
|
+
import process from 'node:process'
|
|
23
|
+
|
|
24
|
+
const BUILTINS = new Set([...builtinModules, ...builtinModules.map((name) => `node:${name}`)])
|
|
25
|
+
|
|
26
|
+
const projectRoot = process.cwd()
|
|
27
|
+
const distDir = join(projectRoot, 'dist')
|
|
28
|
+
|
|
29
|
+
if (!existsSync(distDir)) {
|
|
30
|
+
throw new Error(`dist folder not found at ${distDir} — build the project first`)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Reads and parses a JSON file, returning {} on failure. */
|
|
34
|
+
function readJson (filePath) {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(readFileSync(filePath, 'utf8'))
|
|
37
|
+
} catch {
|
|
38
|
+
return {}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Finds the workspace root by walking up to a package.json with `workspaces`. */
|
|
43
|
+
function findWorkspaceRoot (start) {
|
|
44
|
+
let directory = start
|
|
45
|
+
for (;;) {
|
|
46
|
+
const manifest = readJson(join(directory, 'package.json'))
|
|
47
|
+
if (manifest.workspaces) {
|
|
48
|
+
return directory
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const parent = resolve(directory, '..')
|
|
52
|
+
if (parent === directory) {
|
|
53
|
+
return start
|
|
54
|
+
}
|
|
55
|
+
directory = parent
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Resolves a package name from an import specifier (handles scopes). */
|
|
60
|
+
function packageNameOf (specifier) {
|
|
61
|
+
if (specifier.startsWith('@')) {
|
|
62
|
+
const [scope, name] = specifier.split('/')
|
|
63
|
+
return `${scope}/${name ?? ''}`
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return specifier.split('/', 1)[0]
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Returns whether a specifier is a relative or absolute path import. */
|
|
70
|
+
function isPathSpecifier (specifier) {
|
|
71
|
+
return (
|
|
72
|
+
specifier.startsWith('.') ||
|
|
73
|
+
specifier.startsWith('/') ||
|
|
74
|
+
/^[a-zA-Z]:[/\\]/.test(specifier)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Lists every emitted JS file under a directory. */
|
|
79
|
+
function listJsFiles (directory) {
|
|
80
|
+
const files = []
|
|
81
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
82
|
+
const full = join(directory, entry.name)
|
|
83
|
+
if (entry.isDirectory()) {
|
|
84
|
+
files.push(...listJsFiles(full))
|
|
85
|
+
} else if (/\.(c|m)?js$/i.test(entry.name)) {
|
|
86
|
+
files.push(full)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return files
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Extracts import/require/export specifiers from JS source. */
|
|
94
|
+
function extractSpecifiers (source) {
|
|
95
|
+
const found = new Set()
|
|
96
|
+
const patterns = [
|
|
97
|
+
/\bimport\s+[^'"\n]+\s+from\s+['"]([^'"]+)['"]/g,
|
|
98
|
+
/\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
99
|
+
/\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
100
|
+
/\bexport\s+[^'"\n]+\s+from\s+['"]([^'"]+)['"]/g,
|
|
101
|
+
]
|
|
102
|
+
for (const pattern of patterns) {
|
|
103
|
+
for (const match of source.matchAll(pattern)) {
|
|
104
|
+
if (match[1]) {
|
|
105
|
+
found.add(match[1])
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return [...found]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Maps workspace package names to their declared versions. */
|
|
114
|
+
function resolveWorkspaceVersions (workspaceRoot, rootManifest) {
|
|
115
|
+
const map = new Map()
|
|
116
|
+
for (const pattern of rootManifest.workspaces ?? []) {
|
|
117
|
+
if (!pattern.endsWith('/*')) {
|
|
118
|
+
continue
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const parent = join(workspaceRoot, pattern.slice(0, -2))
|
|
122
|
+
if (!existsSync(parent)) {
|
|
123
|
+
continue
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const child of readdirSync(parent, { withFileTypes: true })) {
|
|
127
|
+
if (!child.isDirectory()) {
|
|
128
|
+
continue
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const manifest = readJson(join(parent, child.name, 'package.json'))
|
|
132
|
+
if (manifest.name && manifest.version) {
|
|
133
|
+
map.set(manifest.name, manifest.version)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return map
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const sourceManifest = readJson(join(projectRoot, 'package.json'))
|
|
142
|
+
const workspaceRoot = findWorkspaceRoot(projectRoot)
|
|
143
|
+
const rootManifest = readJson(join(workspaceRoot, 'package.json'))
|
|
144
|
+
const rootDependencies = {
|
|
145
|
+
...rootManifest.dependencies,
|
|
146
|
+
...rootManifest.optionalDependencies,
|
|
147
|
+
...rootManifest.devDependencies,
|
|
148
|
+
}
|
|
149
|
+
const workspaceVersions = resolveWorkspaceVersions(workspaceRoot, rootManifest)
|
|
150
|
+
|
|
151
|
+
const used = new Set()
|
|
152
|
+
for (const file of listJsFiles(distDir)) {
|
|
153
|
+
for (const specifier of extractSpecifiers(readFileSync(file, 'utf8'))) {
|
|
154
|
+
if (isPathSpecifier(specifier) || BUILTINS.has(specifier)) {
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
used.add(packageNameOf(specifier))
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const dependencies = {}
|
|
162
|
+
const missing = []
|
|
163
|
+
for (const name of [...used].sort((a, b) => a.localeCompare(b))) {
|
|
164
|
+
if (workspaceVersions.has(name)) {
|
|
165
|
+
dependencies[name] = `^${workspaceVersions.get(name)}`
|
|
166
|
+
} else if (rootDependencies[name]) {
|
|
167
|
+
dependencies[name] = rootDependencies[name]
|
|
168
|
+
} else {
|
|
169
|
+
missing.push(name)
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (missing.length > 0) {
|
|
174
|
+
throw new Error(`Missing version for: ${missing.join(', ')} — add them to the root package.json`)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const dist = sourceManifest.monecromanci?.dist ?? {}
|
|
178
|
+
const distManifest = {
|
|
179
|
+
name: sourceManifest.name,
|
|
180
|
+
version: sourceManifest.version,
|
|
181
|
+
description: sourceManifest.description,
|
|
182
|
+
license: sourceManifest.license,
|
|
183
|
+
main: dist.main ?? './index.js',
|
|
184
|
+
types: dist.types ?? './index.d.ts',
|
|
185
|
+
...(dist.bin ? { bin: dist.bin } : {}),
|
|
186
|
+
...(sourceManifest.repository ? { repository: sourceManifest.repository } : {}),
|
|
187
|
+
...(sourceManifest.publishConfig ? { publishConfig: sourceManifest.publishConfig } : {}),
|
|
188
|
+
dependencies,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
writeFileSync(join(distDir, 'package.json'), `${JSON.stringify(distManifest, undefined, 2)}\n`, 'utf8')
|
|
192
|
+
|
|
193
|
+
// CLI bins must be executable scripts: prepend a shebang if the bundler omitted it.
|
|
194
|
+
const shebang = '#!/usr/bin/env node\n'
|
|
195
|
+
for (const binPath of Object.values(dist.bin ?? {})) {
|
|
196
|
+
const binFile = join(distDir, binPath)
|
|
197
|
+
if (existsSync(binFile)) {
|
|
198
|
+
const content = readFileSync(binFile, 'utf8')
|
|
199
|
+
if (!content.startsWith('#!')) {
|
|
200
|
+
writeFileSync(binFile, shebang + content, 'utf8')
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
process.stdout.write(`Wrote dist/package.json for ${distManifest.name} (${Object.keys(dependencies).length} deps)\n`)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builds a Next.js app for one environment and assembles a self-contained drop
|
|
5
|
+
* in `dist-<env>`. The output mode is chosen by NEXT_OUTPUT:
|
|
6
|
+
* - 'standalone' (default): a runnable Node server (`node dist-<env>/server.js`)
|
|
7
|
+
* - 'export': a static site
|
|
8
|
+
*
|
|
9
|
+
* Run per environment with the env file loaded, e.g.:
|
|
10
|
+
* dotenv -e .env.dev -- node ../../tools/next-build.mjs dev
|
|
11
|
+
*/
|
|
12
|
+
import { execSync } from 'node:child_process'
|
|
13
|
+
import { cpSync, existsSync, rmSync } from 'node:fs'
|
|
14
|
+
import { join } from 'node:path'
|
|
15
|
+
import process from 'node:process'
|
|
16
|
+
|
|
17
|
+
const environment = process.argv[2] ?? 'dev'
|
|
18
|
+
const mode = process.env.NEXT_OUTPUT === 'export' ? 'export' : 'standalone'
|
|
19
|
+
const cwd = process.cwd()
|
|
20
|
+
const distDir = join(cwd, `dist-${environment}`)
|
|
21
|
+
|
|
22
|
+
rmSync(distDir, { recursive: true, force: true })
|
|
23
|
+
execSync('next build', { stdio: 'inherit', cwd, env: { ...process.env, NEXT_OUTPUT: mode } })
|
|
24
|
+
|
|
25
|
+
if (mode === 'export') {
|
|
26
|
+
cpSync(join(cwd, 'out'), distDir, { recursive: true })
|
|
27
|
+
} else {
|
|
28
|
+
cpSync(join(cwd, '.next', 'standalone'), distDir, { recursive: true })
|
|
29
|
+
if (existsSync(join(cwd, '.next', 'static'))) {
|
|
30
|
+
cpSync(join(cwd, '.next', 'static'), join(distDir, '.next', 'static'), { recursive: true })
|
|
31
|
+
}
|
|
32
|
+
if (existsSync(join(cwd, 'public'))) {
|
|
33
|
+
cpSync(join(cwd, 'public'), join(distDir, 'public'), { recursive: true })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
process.stdout.write(`Assembled dist-${environment} (mode: ${mode})\n`)
|