| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // @ts-nocheck <-- This is needed as this file is basically a JavaScript script |
| // but with some TypeScript niceness baked in |
| const path = require('path') |
| const fs = require('fs') |
| const { glob } = require('glob') |
| const concurrently = require('concurrently') |
| const child_process = require('child_process') |
| const jsoncParse = require('jsonc-parser').parse |
| |
| const packageData = jsoncParse( |
| fs.readFileSync(path.resolve('package.json'), 'utf8') |
| ) |
| const pkg_version = packageData['version'] |
| |
| function rmFileOrDirectory(path) { |
| if (fs.existsSync(path)) fs.rmSync(path, { recursive: true }) |
| } |
| |
| function genVersionTS() { |
| const version = JSON.stringify(require('../package.json').version).replace( |
| /"/g, |
| "'" |
| ) |
| fs.writeFileSync( |
| './src/version.ts', |
| `/* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| export const LIB_VERSION = ${version} |
| ` |
| ) |
| } |
| |
| const nodeclean = () => ['out', 'dist'].forEach((dir) => rmFileOrDirectory(dir)) |
| |
| const scalaclean = () => |
| glob('**/target', { cwd: '.' }) |
| .then((files) => files.forEach((dir) => rmFileOrDirectory(dir))) |
| .catch((err) => console.log(err)) |
| |
| function watch() { |
| concurrently( |
| ['yarn watch:vite-dev', 'yarn watch:svelte', 'yarn watch:tdmlEditorJS'], |
| { |
| killOthersOn: ['failure'], |
| restartTries: 1, |
| } |
| ) |
| } |
| |
| function package() { |
| const pkg_dir = 'dist/package' |
| |
| // create .vscodeignore to not package all node_modules into the vsix |
| fs.writeFileSync( |
| path.join(pkg_dir, '.vscodeignore'), |
| `# Licensed to the Apache Software Foundation (ASF) under one or more |
| # contributor license agreements. See the NOTICE file distributed with |
| # this work for additional information regarding copyright ownership. |
| # The ASF licenses this file to You under the Apache License, Version 2.0 |
| # (the "License"); you may not use this file except in compliance with |
| # the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| **/node_modules/**/* |
| !node_modules/ |
| !node_modules/**/* |
| ` |
| ) |
| } |
| |
| function packageNamePath(packageName) { |
| return path.join(...packageName.split('/')) |
| } |
| |
| function readPackageVersion(packageRoot) { |
| const packageJsonPath = path.join(packageRoot, 'package.json') |
| if (!fs.existsSync(packageJsonPath)) return undefined |
| |
| try { |
| return JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')).version |
| } catch (err) { |
| console.warn( |
| `[omega-edit] Unable to read package version for ${packageRoot}: ${String( |
| err |
| )}` |
| ) |
| return undefined |
| } |
| } |
| |
| function shouldPatchOmegaEditPackage(packageRoot, expectedVersion, label) { |
| const version = readPackageVersion(packageRoot) |
| if (version === expectedVersion) { |
| return true |
| } |
| |
| const versionLabel = version ?? 'unknown' |
| console.warn( |
| `[omega-edit] Skipping ${label} patch for ${packageRoot}; expected ${expectedVersion}, found ${versionLabel}.` |
| ) |
| return false |
| } |
| |
| function patchOmegaEditClientLogger( |
| packageRoot = 'node_modules/@omega-edit/client' |
| ) { |
| if (!shouldPatchOmegaEditPackage(packageRoot, '2.0.0', 'client logger')) { |
| return |
| } |
| |
| const loggerTargets = [ |
| path.join(packageRoot, 'dist/cjs/logger.js'), |
| path.join(packageRoot, 'dist/esm/logger.js'), |
| ] |
| const transportPattern = |
| /setLogger\(buildLogger\(pino(?:_1\.default)?\.transport\(\{[\s\S]*?\}\)\)\);/ |
| |
| loggerTargets.forEach((loggerPath) => { |
| if (!fs.existsSync(loggerPath)) { |
| console.warn(`[omega-edit] Client logger not found: ${loggerPath}`) |
| return |
| } |
| |
| const source = fs.readFileSync(loggerPath, 'utf-8') |
| const patched = source.replace( |
| transportPattern, |
| 'setLogger(buildLogger(process.stderr));' |
| ) |
| |
| if (patched === source) { |
| if (!source.includes('setLogger(buildLogger(process.stderr));')) { |
| console.warn( |
| `[omega-edit] Unable to patch OmegaEdit client logger at ${loggerPath}; leaving upstream source unchanged.` |
| ) |
| } |
| return |
| } |
| |
| fs.writeFileSync(loggerPath, patched, 'utf-8') |
| }) |
| } |
| |
| function patchOmegaEditServerLocator(searchRoot = 'node_modules') { |
| const serverTargets = glob.sync('**/@omega-edit/server/out/index.js', { |
| cwd: searchRoot, |
| absolute: true, |
| nodir: true, |
| }) |
| const buggyLocator = '.replace("node_modules","")' |
| const knownFixedLocators = [ |
| '.slice(0,-"node_modules".length)', |
| '.slice(0,-12)', |
| ] |
| |
| if (serverTargets.length === 0) { |
| return |
| } |
| |
| serverTargets.forEach((serverPath) => { |
| const packageRoot = path.dirname(path.dirname(serverPath)) |
| if (!shouldPatchOmegaEditPackage(packageRoot, '2.0.0', 'server locator')) { |
| return |
| } |
| |
| const source = fs.readFileSync(serverPath, 'utf-8') |
| const patched = source.replaceAll(buggyLocator, knownFixedLocators[0]) |
| |
| if (patched === source) { |
| if (!knownFixedLocators.some((locator) => source.includes(locator))) { |
| console.warn( |
| `[omega-edit] Unable to patch OmegaEdit server locator at ${serverPath}; leaving upstream source unchanged.` |
| ) |
| } |
| return |
| } |
| |
| fs.writeFileSync(serverPath, patched, 'utf-8') |
| }) |
| } |
| |
| function patchOmegaEditRuntime( |
| packageRoot = 'node_modules/@omega-edit/client', |
| searchRoot = 'node_modules' |
| ) { |
| patchOmegaEditClientLogger(packageRoot) |
| patchOmegaEditServerLocator(searchRoot) |
| } |
| |
| function copyPackageRuntimeTree( |
| packageName, |
| sourcePackageDir, |
| destinationPackageDir, |
| seen = new Set() |
| ) { |
| const visitKey = `${sourcePackageDir}|${destinationPackageDir}` |
| if (seen.has(visitKey)) return |
| seen.add(visitKey) |
| |
| if (!fs.existsSync(sourcePackageDir)) { |
| throw new Error( |
| `Package source not found for ${packageName}: ${sourcePackageDir}` |
| ) |
| } |
| |
| rmFileOrDirectory(destinationPackageDir) |
| fs.mkdirSync(path.dirname(destinationPackageDir), { recursive: true }) |
| fs.cpSync(sourcePackageDir, destinationPackageDir, { |
| recursive: true, |
| force: true, |
| }) |
| |
| const packageJsonPath = path.join(sourcePackageDir, 'package.json') |
| const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8')) |
| const dependencies = Object.keys(packageJson.dependencies || {}) |
| |
| if (dependencies.length === 0) return |
| |
| const destinationNodeModulesDir = path.join( |
| destinationPackageDir, |
| 'node_modules' |
| ) |
| |
| dependencies.forEach((dependencyName) => { |
| const sourceDependencyDirCandidates = [ |
| path.join( |
| sourcePackageDir, |
| 'node_modules', |
| packageNamePath(dependencyName) |
| ), |
| path.join('node_modules', packageNamePath(dependencyName)), |
| ] |
| const sourceDependencyDir = sourceDependencyDirCandidates.find( |
| (candidate) => fs.existsSync(candidate) |
| ) |
| |
| if (!sourceDependencyDir) { |
| throw new Error( |
| `Unable to resolve runtime dependency ${dependencyName} for ${packageName}` |
| ) |
| } |
| |
| copyPackageRuntimeTree( |
| dependencyName, |
| sourceDependencyDir, |
| path.join(destinationNodeModulesDir, packageNamePath(dependencyName)), |
| seen |
| ) |
| }) |
| } |
| |
| function syncOmegaEditClientRuntime() { |
| const clientPackageName = '@omega-edit/client' |
| const sourceClientDir = path.join( |
| 'node_modules', |
| packageNamePath(clientPackageName) |
| ) |
| const destinationClientDir = path.join( |
| 'dist/package/node_modules', |
| packageNamePath(clientPackageName) |
| ) |
| |
| patchOmegaEditRuntime(sourceClientDir, 'node_modules') |
| copyPackageRuntimeTree( |
| clientPackageName, |
| sourceClientDir, |
| destinationClientDir |
| ) |
| patchOmegaEditRuntime(destinationClientDir, 'dist/package/node_modules') |
| } |
| |
| function packageVsix() { |
| const vsceCommand = |
| process.platform === 'win32' |
| ? path.resolve('node_modules', '.bin', 'vsce.cmd') |
| : path.resolve('node_modules', '.bin', 'vsce') |
| |
| const result = child_process.spawnSync( |
| vsceCommand, |
| ['package', '--out', '../../'], |
| { |
| cwd: 'dist/package', |
| stdio: 'inherit', |
| shell: process.platform === 'win32', |
| } |
| ) |
| |
| if (result.error) { |
| console.error(result.error) |
| process.exit(1) |
| } |
| |
| process.exit(result.status === null ? 1 : result.status) |
| } |
| |
| function getScalaVersions() { |
| const scalaVersions = ['2.12', '2.13'] |
| |
| // The scala 3 version of the debugger should only exist if JDK >= 17 is being used |
| if (fs.existsSync(`debugger/target/jvm-3/universal/stage`)) { |
| scalaVersions.push('3') |
| } |
| |
| return scalaVersions |
| } |
| |
| function moveDebuggers() { |
| getScalaVersions().forEach(async (scalaVersion) => { |
| const serverPackage = `daffodil-debugger-${scalaVersion}-${pkg_version}` |
| const jvmFolderName = `jvm-${scalaVersion}` |
| const stageFilePath = path.resolve( |
| `debugger/target/${jvmFolderName}/universal/stage` |
| ) |
| |
| const serverPackageFolder = path.join('dist/debuggers', serverPackage) |
| |
| // remove debugger package folder if exists |
| if (fs.existsSync(serverPackageFolder)) { |
| fs.rmSync(serverPackageFolder, { recursive: true, force: true }) |
| } |
| |
| // Copy staged debugger files to desired location |
| fs.cpSync(stageFilePath, serverPackageFolder, { recursive: true }) |
| }) |
| } |
| |
| /* START SECTION: Update version */ |
| // helper function to get the version passed in |
| function parseArgs() { |
| const args = process.argv.slice(1) |
| |
| for (let i = 0; i < args.length; i++) { |
| if ((args[i] === '-v' || args[i] == '--version') && i + 1 < args.length) { |
| return args[i + 1] |
| } |
| } |
| |
| return null |
| } |
| |
| function updatePackageJsonVersion(version) { |
| const packageJsonPath = 'package.json' |
| |
| if (!fs.existsSync(packageJsonPath)) { |
| console.error('Error: package.json not found') |
| process.exit(1) |
| } |
| |
| const pkgRaw = fs.readFileSync(packageJsonPath, 'utf-8') |
| const pkg = JSON.parse(pkgRaw) |
| pkg.version = version |
| |
| fs.writeFileSync( |
| packageJsonPath, |
| JSON.stringify(pkg, null, 2) + '\n', |
| 'utf-8' |
| ) |
| console.log(`package.json version updated to ${version}`) |
| } |
| |
| function updateVersionFile(version) { |
| fs.writeFileSync('VERSION', version + '\n', 'utf-8') |
| console.log(`VERSION updated to ${version}`) |
| } |
| |
| function updateVersion() { |
| let newVersion = parseArgs() |
| |
| if (!newVersion) { |
| console.error('Error: Please provide a version using -v or --version') |
| process.exit(1) |
| } |
| |
| if (newVersion.startsWith('v')) { |
| newVersion = newVersion.slice(1) |
| } |
| |
| updatePackageJsonVersion(newVersion) |
| updateVersionFile(newVersion) |
| } |
| /* END SECTION: Update version */ |
| |
| /* START SECTION: LICENSE related methods */ |
| function getLicenseData() { |
| return JSON.parse( |
| child_process |
| .execSync( |
| `yarn licenses list --json --prod | jq 'select(.type == "table").data.body'` |
| ) |
| .toString() |
| ) |
| } |
| |
| function checkMissingLicenseData() { |
| const licenses = getLicenseData() |
| |
| const packageLicenseData = fs.readFileSync('build/package/LICENSE', 'utf-8') |
| const packageLicenseLines = packageLicenseData.split('\n') |
| |
| const packageNoticeData = fs.readFileSync('build/package/NOTICE', 'utf-8') |
| const packageNoticeLines = packageNoticeData.split('\n') |
| |
| const packageNoNoticeData = fs.readFileSync('build/package/NONOTICE', 'utf-8') |
| const packageNoNoticeLines = packageNoNoticeData.split('\n') |
| |
| const missingLicenseData = [] |
| |
| licenses.forEach((license) => { |
| if ( |
| packageLicenseLines |
| .map((line) => line.startsWith('-') && line.includes(license[0])) |
| .some(Boolean) || |
| packageNoticeLines |
| .map((line) => line.startsWith('-') && line.includes(license[0])) |
| .some(Boolean) || |
| packageNoNoticeLines |
| .map((line) => line.startsWith('-') && line.includes(license[0])) |
| .some(Boolean) |
| ) |
| return |
| |
| missingLicenseData.push(license[0]) |
| }) |
| |
| if (missingLicenseData.length > 0) { |
| console.log('Missing LICENSE data for the following dependencies') |
| missingLicenseData.forEach((licenseName) => |
| console.log(` - ${licenseName}`) |
| ) |
| process.exit(1) |
| } else { |
| console.log('No missing LICENSE data!') |
| } |
| } |
| |
| function checkLicenseCompatibility() { |
| const licenses = getLicenseData() |
| |
| const licenseDataFileData = JSON.parse( |
| fs.readFileSync('build/license_data.json', 'utf-8') |
| ) |
| |
| const allowedLicenseTypes = licenseDataFileData.allowedLiceneseTypes |
| const allowedLicenses = licenseDataFileData.packages |
| .filter((data) => data.allowed) |
| .map((data) => data.name) |
| |
| const badLicenses = [] |
| |
| licenses.forEach((license) => { |
| const licenseCompatibile = |
| allowedLicenseTypes.filter((licenseType) => |
| license[2].includes(licenseType) |
| ).length > 0 |
| ? true |
| : false |
| |
| if (!licenseCompatibile && !allowedLicenses.includes(license[0])) { |
| badLicenses.push(license) |
| } |
| }) |
| |
| if (badLicenses.length > 0) { |
| console.log('The follow dependencies have not ASF approved LICENCES:') |
| badLicenses.forEach((license) => |
| console.log(` - ${license[0]} -> ${license[2]}`) |
| ) |
| process.exit(1) |
| } else { |
| console.log('All dependency LICENSES are compatibile!') |
| } |
| } |
| /* END SECTION: LICENSE related methods */ |
| |
| module.exports = { |
| genVersionTS: genVersionTS, |
| nodeclean: nodeclean, |
| scalaclean: scalaclean, |
| updateVersion: updateVersion, |
| watch: watch, |
| package: package, |
| patchOmegaEditClientLogger: patchOmegaEditClientLogger, |
| patchOmegaEditServerLocator: patchOmegaEditServerLocator, |
| patchOmegaEditRuntime: patchOmegaEditRuntime, |
| syncOmegaEditClientRuntime: syncOmegaEditClientRuntime, |
| packageVsix: packageVsix, |
| checkMissingLicenseData: checkMissingLicenseData, |
| checkLicenseCompatibility: checkLicenseCompatibility, |
| moveDebuggers: moveDebuggers, |
| } |