diff --git a/scripts/generate-data.mjs b/scripts/generate-data.mjs index 3980b67..f91219c 100644 --- a/scripts/generate-data.mjs +++ b/scripts/generate-data.mjs @@ -1,11 +1,11 @@ import cluster from 'node:cluster'; -import os from 'node:os'; +import { availableParallelism } from 'node:os'; import resources from '../data/resources.mjs'; import generateData from '../index.mjs'; // ----------------------------------------------------------------------------- -const numCPUs = os.cpus().length; +const numCPUs = Math.min(4, availableParallelism()); const pad = (number) => { return String(number).padStart(2, '0'); diff --git a/scripts/utils.mjs b/scripts/utils.mjs index 721c5c6..a194f4a 100644 --- a/scripts/utils.mjs +++ b/scripts/utils.mjs @@ -76,6 +76,19 @@ const samePropertyRuns = (codePointProperties) => { return result; }; +// Only write the file if its content has changed. +// Reading files is cheaper than writing files, and most files don’t change between builds. +const writeFileIfChanged = (filePath, content) => { + try { + if (fs.readFileSync(filePath, 'utf8') === content) { + return; + } + } catch { + // Ignore errors such ENOENT (file not found) + } + fs.writeFileSync(filePath, content); +}; + const writeFiles = (options) => { const version = options.version; const subType = options.subType; @@ -147,11 +160,11 @@ const writeFiles = (options) => { if (type === 'Sequence_Property' || isNameAliases) { const sequences = codePoints; const output = `import { gunzipSync } from 'node:zlib';\n\nexport default ${ gzipInline(sequences) };\n`; - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'index.mjs'), output ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'index.d.mts'), type === 'Sequence_Property' ? `declare const data: string[];\nexport default data;\n` @@ -167,19 +180,19 @@ const writeFiles = (options) => { let symbolsType = 'string[]'; if (!isCaseFoldingOrMapping) { const encodedRanges = codePoints instanceof regenerate ? encodeRegenerate(codePoints) : encodeRanges(codePoints); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'ranges.mjs'), `import decodeRanges from '../../decode-ranges.mjs';\n\nexport default decodeRanges('${encodedRanges}');\n` ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'ranges.d.mts'), 'import type { UnicodeRange } from "../../decode-ranges.mjs";\n\ndeclare const ranges: UnicodeRange[];\nexport default ranges;\n' ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'regex.mjs'), 'export default /' + regenerate(codePoints).toString() + '/;\n' ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'regex.d.mts'), 'declare const regex: RegExp;\nexport default regex;\n' ); @@ -213,19 +226,19 @@ const writeFiles = (options) => { } symbolsType = 'Map'; } - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'code-points.mjs'), codePointsFileContent ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'code-points.d.mts'), `declare const codePoints: ${ codePointsType };\nexport default codePoints;\n` ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'symbols.mjs'), symbolsFileContent ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'symbols.d.mts'), `declare const symbols: ${ symbolsType };\nexport default symbols;\n` ); @@ -249,11 +262,11 @@ const writeFiles = (options) => { JSON.stringify(bidiMirroringGlyphFlatPairs) }.map((v, i, a) => pair(i & 1, a[i ^ 1], v)));\n` ].join('\n'); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'index.mjs'), output ); - fs.writeFileSync( + writeFileIfChanged( path.resolve(dir, 'index.d.mts'), `declare const data: Map;\nexport default data;\n` ); @@ -275,8 +288,8 @@ const writeFiles = (options) => { const output = `import { gunzipSync } from 'node:zlib';\nimport decodePropertyMap from '../decode-property-map.mjs';\n\nexport default decodePropertyMap(${gzipInline( flatRuns )});\n`; - fs.writeFileSync(path.resolve(dir, 'index.mjs'), output); - fs.writeFileSync(path.resolve(dir, 'index.d.mts'), `declare const map: Map;\nexport default map;\n`); + writeFileIfChanged(path.resolve(dir, 'index.mjs'), output); + writeFileIfChanged(path.resolve(dir, 'index.d.mts'), `declare const map: Map;\nexport default map;\n`); } } return dirMap;