@k-l-lambda/lilypond-node 2.24.4
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/lib/index.d.ts +72 -0
- package/lib/index.js +125 -0
- package/package.json +56 -0
- package/scripts/install.js +121 -0
- package/scripts/postinstall.js +120 -0
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LilyPond Node.js Native Addon
|
|
3
|
+
*
|
|
4
|
+
* TypeScript definitions for the lilypond-node package.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for the engrave function
|
|
9
|
+
*/
|
|
10
|
+
export interface EngraveOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Callback invoked when an SVG file is generated
|
|
13
|
+
* @param filename - The name of the SVG file (e.g., "output.svg")
|
|
14
|
+
* @param content - The SVG content as a string
|
|
15
|
+
*/
|
|
16
|
+
onSVG?: (filename: string, content: string) => void;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Callback invoked when a MIDI file is generated
|
|
20
|
+
* @param filename - The name of the MIDI file (e.g., "output.midi")
|
|
21
|
+
* @param data - The MIDI data as an ArrayBuffer
|
|
22
|
+
*/
|
|
23
|
+
onMIDI?: (filename: string, data: ArrayBuffer) => void;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Callback invoked for log messages from LilyPond
|
|
27
|
+
* @param message - The log message
|
|
28
|
+
*/
|
|
29
|
+
log?: (message: string) => void;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Additional include paths for \include commands
|
|
33
|
+
*/
|
|
34
|
+
includeFolders?: string[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Engrave LilyPond code to SVG and/or MIDI
|
|
39
|
+
*
|
|
40
|
+
* @param lyCode - LilyPond source code
|
|
41
|
+
* @param options - Engrave options
|
|
42
|
+
* @returns Promise resolving to exit code (0 = success, 1 = warning, other = error)
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```typescript
|
|
46
|
+
* import { engrave } from 'lilypond-node';
|
|
47
|
+
*
|
|
48
|
+
* const lyCode = `\\version "2.24.4"
|
|
49
|
+
* { c' d' e' f' g' }
|
|
50
|
+
* `;
|
|
51
|
+
*
|
|
52
|
+
* const result = await engrave(lyCode, {
|
|
53
|
+
* onSVG: (filename, content) => {
|
|
54
|
+
* console.log('SVG:', filename, content.length, 'bytes');
|
|
55
|
+
* }
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* console.log('Exit code:', result);
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function engrave(lyCode: string, options?: EngraveOptions): Promise<number>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get the LilyPond data directory path
|
|
65
|
+
* @returns Path to LILYPOND_DATADIR
|
|
66
|
+
*/
|
|
67
|
+
export function getDataDir(): string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* LilyPond version bundled with this package
|
|
71
|
+
*/
|
|
72
|
+
export const version: string;
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LilyPond Node.js Native Addon
|
|
3
|
+
*
|
|
4
|
+
* A Node.js native addon for LilyPond music engraving.
|
|
5
|
+
* Converts LilyPond notation to SVG and MIDI output.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
|
|
11
|
+
// Find the module root directory
|
|
12
|
+
const moduleRoot = path.join(__dirname, '..');
|
|
13
|
+
|
|
14
|
+
// Possible locations for the native addon
|
|
15
|
+
const addonPaths = [
|
|
16
|
+
// Development build location
|
|
17
|
+
path.join(moduleRoot, 'build', 'Release', 'lilypond.node'),
|
|
18
|
+
path.join(moduleRoot, 'build', 'Debug', 'lilypond.node'),
|
|
19
|
+
// cmake-js default output
|
|
20
|
+
path.join(moduleRoot, 'build', 'lilypond.node'),
|
|
21
|
+
// Legacy output location
|
|
22
|
+
path.join(moduleRoot, 'output', 'lilypond.node'),
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
// Find and load the native addon
|
|
26
|
+
let addon = null;
|
|
27
|
+
let addonPath = null;
|
|
28
|
+
|
|
29
|
+
for (const p of addonPaths) {
|
|
30
|
+
if (fs.existsSync(p)) {
|
|
31
|
+
addonPath = p;
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!addonPath) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
'LilyPond native addon not found. ' +
|
|
39
|
+
'Please run "npm run build" to compile the addon.'
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Set up LILYPOND_DATADIR if not already set
|
|
44
|
+
if (!process.env.LILYPOND_DATADIR) {
|
|
45
|
+
const sharePaths = [
|
|
46
|
+
// Output directory has complete build artifacts
|
|
47
|
+
path.join(moduleRoot, 'output', 'share', 'lilypond', 'current'),
|
|
48
|
+
// Package share directory (for npm install)
|
|
49
|
+
path.join(moduleRoot, 'share', 'lilypond', 'current'),
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
for (const p of sharePaths) {
|
|
53
|
+
if (fs.existsSync(p)) {
|
|
54
|
+
process.env.LILYPOND_DATADIR = p;
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (!process.env.LILYPOND_DATADIR) {
|
|
60
|
+
throw new Error(
|
|
61
|
+
'LilyPond data directory not found. ' +
|
|
62
|
+
'Please set LILYPOND_DATADIR or run "npm run postinstall".'
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Load the addon
|
|
68
|
+
addon = require(addonPath);
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Engrave LilyPond code to SVG and/or MIDI
|
|
72
|
+
*
|
|
73
|
+
* @param {string} lyCode - LilyPond source code
|
|
74
|
+
* @param {Object} [options] - Engrave options
|
|
75
|
+
* @param {Function} [options.onSVG] - Callback for SVG output: (filename, content) => void
|
|
76
|
+
* @param {Function} [options.onMIDI] - Callback for MIDI output: (filename, data) => void
|
|
77
|
+
* @param {Function} [options.log] - Callback for log messages: (message) => void
|
|
78
|
+
* @param {string[]} [options.includeFolders] - Additional include paths for \include commands
|
|
79
|
+
* @returns {Promise<number>} Promise resolving to exit code (0 = success, 1 = warning, other = error)
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const lilypond = require('lilypond-node');
|
|
83
|
+
*
|
|
84
|
+
* const lyCode = `\\version "2.24.4"
|
|
85
|
+
* { c' d' e' f' g' }
|
|
86
|
+
* `;
|
|
87
|
+
*
|
|
88
|
+
* lilypond.engrave(lyCode, {
|
|
89
|
+
* onSVG: (filename, content) => {
|
|
90
|
+
* console.log('SVG:', filename, content.length, 'bytes');
|
|
91
|
+
* },
|
|
92
|
+
* onMIDI: (filename, data) => {
|
|
93
|
+
* console.log('MIDI:', filename, data.byteLength, 'bytes');
|
|
94
|
+
* },
|
|
95
|
+
* log: (msg) => console.log(msg)
|
|
96
|
+
* }).then((code) => {
|
|
97
|
+
* console.log('Finished with code:', code);
|
|
98
|
+
* });
|
|
99
|
+
*/
|
|
100
|
+
function engrave(lyCode, options = {}) {
|
|
101
|
+
if (typeof lyCode !== 'string') {
|
|
102
|
+
return Promise.reject(new TypeError('lyCode must be a string'));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return addon.engrave(lyCode, options);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Get the LilyPond data directory path
|
|
110
|
+
* @returns {string} Path to LILYPOND_DATADIR
|
|
111
|
+
*/
|
|
112
|
+
function getDataDir() {
|
|
113
|
+
return process.env.LILYPOND_DATADIR;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* LilyPond version
|
|
118
|
+
*/
|
|
119
|
+
const version = '2.24.4';
|
|
120
|
+
|
|
121
|
+
module.exports = {
|
|
122
|
+
engrave,
|
|
123
|
+
getDataDir,
|
|
124
|
+
version,
|
|
125
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@k-l-lambda/lilypond-node",
|
|
3
|
+
"version": "2.24.4",
|
|
4
|
+
"description": "LilyPond music engraving as a Node.js native addon",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"types": "lib/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"install": "node scripts/install.js",
|
|
9
|
+
"build": "cmake-js build",
|
|
10
|
+
"rebuild": "cmake-js rebuild",
|
|
11
|
+
"clean": "cmake-js clean",
|
|
12
|
+
"test": "node test/test.js",
|
|
13
|
+
"postinstall": "node scripts/postinstall.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"lilypond",
|
|
17
|
+
"music",
|
|
18
|
+
"engraving",
|
|
19
|
+
"notation",
|
|
20
|
+
"svg",
|
|
21
|
+
"midi",
|
|
22
|
+
"sheet-music"
|
|
23
|
+
],
|
|
24
|
+
"author": "K.L. Lambda",
|
|
25
|
+
"license": "GPL-3.0",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://gitlab.com/k.l.lambda/lilypond.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://gitlab.com/k.l.lambda/lilypond/-/issues"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://gitlab.com/k.l.lambda/lilypond#readme",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=22.0.0"
|
|
36
|
+
},
|
|
37
|
+
"os": [
|
|
38
|
+
"linux"
|
|
39
|
+
],
|
|
40
|
+
"cpu": [
|
|
41
|
+
"x64"
|
|
42
|
+
],
|
|
43
|
+
"dependencies": {},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"cmake-js": "^7.3.0"
|
|
46
|
+
},
|
|
47
|
+
"binary": {
|
|
48
|
+
"host": "https://gitlab.com/k.l.lambda/lilypond/-/jobs/artifacts",
|
|
49
|
+
"remote_path": "/{version}/raw",
|
|
50
|
+
"package_name": "lilypond-node-{platform}-{arch}-node{node_abi}.tar.gz"
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"lib/",
|
|
54
|
+
"scripts/"
|
|
55
|
+
]
|
|
56
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Install script for lilypond-node
|
|
5
|
+
*
|
|
6
|
+
* Downloads prebuilt binary from GitLab artifacts or falls back to source build.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const https = require('https');
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
|
|
14
|
+
const pkg = require('../package.json');
|
|
15
|
+
const moduleRoot = path.join(__dirname, '..');
|
|
16
|
+
|
|
17
|
+
// Check if prebuilt binary already exists
|
|
18
|
+
const outputDir = path.join(moduleRoot, 'output');
|
|
19
|
+
const addonPath = path.join(outputDir, 'lilypond.node');
|
|
20
|
+
|
|
21
|
+
if (fs.existsSync(addonPath)) {
|
|
22
|
+
console.log('lilypond-node: Prebuilt binary already exists.');
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Platform detection
|
|
27
|
+
const platform = process.platform;
|
|
28
|
+
const arch = process.arch;
|
|
29
|
+
const nodeVersion = process.versions.node.split('.')[0];
|
|
30
|
+
|
|
31
|
+
console.log(`lilypond-node: Installing for ${platform}-${arch} (Node ${nodeVersion})`);
|
|
32
|
+
|
|
33
|
+
// Check supported platform
|
|
34
|
+
if (platform !== 'linux' || arch !== 'x64') {
|
|
35
|
+
console.error(`lilypond-node: Unsupported platform: ${platform}-${arch}`);
|
|
36
|
+
console.error('Currently only linux-x64 is supported.');
|
|
37
|
+
console.error('You can try building from source with: npm run build');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (parseInt(nodeVersion) < 22) {
|
|
42
|
+
console.error(`lilypond-node: Node.js ${nodeVersion} is not supported.`);
|
|
43
|
+
console.error('Please use Node.js 22 or later.');
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// GitLab artifacts URL
|
|
48
|
+
// Format: https://gitlab.com/k.l.lambda/lilypond/-/jobs/artifacts/develop/raw/lilypond-node-linux-x64.tar.gz?job=node-addon-linux-x64
|
|
49
|
+
const gitlabProject = 'k.l.lambda/lilypond';
|
|
50
|
+
const branch = 'develop';
|
|
51
|
+
const artifactName = `lilypond-node-linux-x64.tar.gz`;
|
|
52
|
+
const jobName = 'node-addon-linux-x64';
|
|
53
|
+
|
|
54
|
+
const downloadUrl = `https://gitlab.com/${gitlabProject}/-/jobs/artifacts/${branch}/raw/${artifactName}?job=${jobName}`;
|
|
55
|
+
|
|
56
|
+
console.log(`lilypond-node: Downloading prebuilt binary...`);
|
|
57
|
+
console.log(` URL: ${downloadUrl}`);
|
|
58
|
+
|
|
59
|
+
// Download function with redirect support
|
|
60
|
+
function download(url, dest) {
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const file = fs.createWriteStream(dest);
|
|
63
|
+
|
|
64
|
+
function handleResponse(response) {
|
|
65
|
+
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
66
|
+
// Follow redirect
|
|
67
|
+
https.get(response.headers.location, handleResponse).on('error', reject);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (response.statusCode !== 200) {
|
|
72
|
+
reject(new Error(`Download failed: HTTP ${response.statusCode}`));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
response.pipe(file);
|
|
77
|
+
file.on('finish', () => {
|
|
78
|
+
file.close();
|
|
79
|
+
resolve();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
https.get(url, handleResponse).on('error', reject);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function install() {
|
|
88
|
+
const tarPath = path.join(moduleRoot, artifactName);
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
// Download
|
|
92
|
+
await download(downloadUrl, tarPath);
|
|
93
|
+
console.log('lilypond-node: Download complete.');
|
|
94
|
+
|
|
95
|
+
// Extract
|
|
96
|
+
console.log('lilypond-node: Extracting...');
|
|
97
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
98
|
+
|
|
99
|
+
execSync(`tar xzf "${tarPath}" -C "${moduleRoot}"`, { stdio: 'inherit' });
|
|
100
|
+
|
|
101
|
+
// Clean up
|
|
102
|
+
fs.unlinkSync(tarPath);
|
|
103
|
+
|
|
104
|
+
// Verify
|
|
105
|
+
if (fs.existsSync(addonPath)) {
|
|
106
|
+
console.log('lilypond-node: Installation complete.');
|
|
107
|
+
} else {
|
|
108
|
+
throw new Error('Addon not found after extraction');
|
|
109
|
+
}
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.error(`lilypond-node: Failed to download prebuilt binary.`);
|
|
112
|
+
console.error(` Error: ${err.message}`);
|
|
113
|
+
console.error('');
|
|
114
|
+
console.error('You can try building from source:');
|
|
115
|
+
console.error(' 1. Clone the full lilypond repo');
|
|
116
|
+
console.error(' 2. cd node-addon && npm run build');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
install();
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Postinstall script for lilypond-node
|
|
5
|
+
*
|
|
6
|
+
* This script sets up the LilyPond share directory with required files:
|
|
7
|
+
* - scm/ - Scheme modules (including build-generated files)
|
|
8
|
+
* - ly/ - LilyPond include files
|
|
9
|
+
* - ps/ - PostScript support files
|
|
10
|
+
* - fonts/ - Music fonts (optional, can use system fonts)
|
|
11
|
+
*
|
|
12
|
+
* Note: For development, the output/ directory contains the complete build.
|
|
13
|
+
* For npm install, files should be copied from the build output.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const moduleRoot = path.join(__dirname, '..');
|
|
20
|
+
const shareDir = path.join(moduleRoot, 'share', 'lilypond', 'current');
|
|
21
|
+
|
|
22
|
+
// Check if output directory already exists (development build)
|
|
23
|
+
const outputShare = path.join(moduleRoot, 'output', 'share', 'lilypond', 'current');
|
|
24
|
+
if (fs.existsSync(outputShare)) {
|
|
25
|
+
console.log('LilyPond postinstall: Using existing output directory.');
|
|
26
|
+
console.log(` LILYPOND_DATADIR: ${outputShare}`);
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Source directories (relative to module root)
|
|
31
|
+
const sourceDirs = ['scm', 'ly', 'ps'];
|
|
32
|
+
|
|
33
|
+
console.log('LilyPond postinstall: Setting up share directory...');
|
|
34
|
+
|
|
35
|
+
// Create share directory structure
|
|
36
|
+
const dirs = ['share', 'share/lilypond', 'share/lilypond/current'];
|
|
37
|
+
for (const dir of dirs) {
|
|
38
|
+
const fullPath = path.join(moduleRoot, dir);
|
|
39
|
+
if (!fs.existsSync(fullPath)) {
|
|
40
|
+
fs.mkdirSync(fullPath, { recursive: true });
|
|
41
|
+
console.log(' Created:', dir);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Copy source directories to share
|
|
46
|
+
for (const dir of sourceDirs) {
|
|
47
|
+
const srcPath = path.join(moduleRoot, dir);
|
|
48
|
+
const destPath = path.join(shareDir, dir);
|
|
49
|
+
|
|
50
|
+
if (!fs.existsSync(srcPath)) {
|
|
51
|
+
console.log(` Warning: Source directory not found: ${dir}`);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (fs.existsSync(destPath)) {
|
|
56
|
+
console.log(` Skip: ${dir} (already exists)`);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Copy directory recursively
|
|
61
|
+
copyDirSync(srcPath, destPath);
|
|
62
|
+
console.log(` Copied: ${dir}`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Create scm/lily/ subdirectory for Guile module loading
|
|
66
|
+
// Guile expects modules in (lily xxx) to be at scm/lily/xxx.scm
|
|
67
|
+
const scmSrcDir = path.join(shareDir, 'scm');
|
|
68
|
+
const lilyModuleDir = path.join(scmSrcDir, 'lily');
|
|
69
|
+
if (fs.existsSync(scmSrcDir) && !fs.existsSync(lilyModuleDir)) {
|
|
70
|
+
fs.mkdirSync(lilyModuleDir, { recursive: true });
|
|
71
|
+
// Copy all .scm files from scm/ to scm/lily/
|
|
72
|
+
const scmFiles = fs.readdirSync(scmSrcDir).filter(f => f.endsWith('.scm'));
|
|
73
|
+
for (const file of scmFiles) {
|
|
74
|
+
fs.copyFileSync(path.join(scmSrcDir, file), path.join(lilyModuleDir, file));
|
|
75
|
+
}
|
|
76
|
+
console.log(` Created: scm/lily/ module directory (${scmFiles.length} files)`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Check for fonts
|
|
80
|
+
const fontsDir = path.join(shareDir, 'fonts');
|
|
81
|
+
if (!fs.existsSync(fontsDir)) {
|
|
82
|
+
console.log('');
|
|
83
|
+
console.log(' Note: Fonts directory not found.');
|
|
84
|
+
console.log(' You may need to copy fonts from a LilyPond installation:');
|
|
85
|
+
console.log(' cp -r /usr/share/lilypond/*/fonts ' + shareDir + '/');
|
|
86
|
+
console.log(' Or set LILYPOND_DATADIR to a system LilyPond installation.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Check for build-generated files
|
|
90
|
+
const fontEncodings = path.join(lilyModuleDir, 'font-encodings.scm');
|
|
91
|
+
if (!fs.existsSync(fontEncodings)) {
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log(' Warning: font-encodings.scm not found.');
|
|
94
|
+
console.log(' This file is generated during the LilyPond build process.');
|
|
95
|
+
console.log(' For development, run: make -C build');
|
|
96
|
+
console.log(' Then copy: cp -r build/out/share/lilypond/current/* share/lilypond/current/');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log('');
|
|
100
|
+
console.log('LilyPond postinstall complete.');
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Recursively copy a directory
|
|
104
|
+
*/
|
|
105
|
+
function copyDirSync(src, dest) {
|
|
106
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
107
|
+
|
|
108
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
109
|
+
|
|
110
|
+
for (const entry of entries) {
|
|
111
|
+
const srcPath = path.join(src, entry.name);
|
|
112
|
+
const destPath = path.join(dest, entry.name);
|
|
113
|
+
|
|
114
|
+
if (entry.isDirectory()) {
|
|
115
|
+
copyDirSync(srcPath, destPath);
|
|
116
|
+
} else {
|
|
117
|
+
fs.copyFileSync(srcPath, destPath);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|