blob: 8a634890d4cb26ac537ad549e795bc9d154c82fb [file]
/*
* 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.
*/
import { defineConfig } from 'vite'
import path from 'node:path'
import fs from 'node:fs'
import { builtinModules } from 'node:module'
import { parse as jsoncParse } from 'jsonc-parser'
import { fileURLToPath } from 'node:url'
import unzip from 'unzip-stream'
import { pipeline } from 'stream/promises'
import { Transform } from 'stream'
import cliProgress from 'cli-progress'
import pc from 'picocolors' // same color lib used by Vite
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const pkg_dir = 'dist/package'
const localModulePath = (moduleName) =>
path.resolve(__dirname, 'src', moduleName)
const localModuleAliases = {
dataEditor: localModulePath('dataEditor'),
tdmlEditor: localModulePath('tdmlEditor'),
language: localModulePath('language'),
launchWizard: localModulePath('launchWizard/launchWizard'),
infoset: localModulePath('infoset'),
rootCompletion: localModulePath('rootCompletion'),
}
const packageData = jsoncParse(
fs.readFileSync(path.resolve('package.json'), 'utf8')
)
const pkg_version = packageData['version']
const defaultDaffodilVersion =
packageData['contributes']['debuggers'][0]['configurationAttributes'][
'launch'
]['properties']['dfdlDebugger']['properties']['daffodilVersion']['default']
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 copyDebuggerOutAfterBuild() {
return {
name: 'copy-debugger-package',
apply: 'build',
async buildStart() {
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 })
})
},
}
}
// Helper function to download and extract with a progress bar. This was specifically designed to match the output
// style of vite.
async function downloadAndExtract(title, url, targetDir) {
console.log(pc.cyan(`\n▶ Starting download for ${title}...\n`))
const res = await fetch(url)
if (!res.ok || !res.body) {
throw new Error(
`Failed to download ${url}: ${res.status} ${res.statusText}`
)
}
const totalBytes = Number(res.headers.get('content-length')) || 0
let downloaded = 0
// Create a CLI progress bar (Vite aesthetic)
const bar = new cliProgress.SingleBar(
{
format: `${pc.bold(title)} ${pc.cyan('[{bar}]')} ${pc.green('{percentage}%')} | {value}/{total} bytes`,
barCompleteChar: '█',
barIncompleteChar: '░',
hideCursor: true,
},
cliProgress.Presets.shades_classic
)
if (totalBytes > 0) {
bar.start(totalBytes, 0)
} else {
console.log(pc.dim('Downloading (unknown size)...'))
}
// Track download progress
const progressStream = new Transform({
transform(chunk, _encoding, callback) {
downloaded += chunk.length
if (totalBytes > 0) {
bar.update(downloaded)
} else if (downloaded % 5_000_000 < chunk.length) {
process.stdout.write('.')
}
callback(null, chunk)
},
})
await fs.promises.mkdir(targetDir, { recursive: true })
// Stream download → progress tracker → unzipper
await pipeline(res.body, progressStream, unzip.Extract({ path: targetDir }))
if (totalBytes > 0) bar.update(totalBytes)
bar.stop()
const check = pc.green(pc.bold('✓'))
console.log(
`${check} ${pc.bold(pc.green(title))} successfully extracted to ${pc.dim(targetDir)}\n`
)
}
function downloadAndExtractDefaultVersionOfDaffodil(mode) {
return {
name: 'download-extract-default-version-of-daffodil',
apply: 'build',
async buildStart() {
const url = `https://www.apache.org/dyn/closer.lua/download/daffodil/${defaultDaffodilVersion}/bin/apache-daffodil-${defaultDaffodilVersion}-bin.zip`
const destFolder =
mode == 'production' ? `${pkg_dir}/dist/daffodil` : 'dist/daffodil'
await downloadAndExtract('Daffodil CLI JARs', url, destFolder)
},
}
}
async function copyToPkgDirPlugin() {
const patterns = [
{ from: 'README.md', to: `${pkg_dir}/README.md` },
{ from: 'build/package/LICENSE', to: `${pkg_dir}/LICENSE` },
{ from: 'build/package/NOTICE', to: `${pkg_dir}/NOTICE` },
{ from: 'dist/views/', to: `${pkg_dir}/dist/views/` },
{ from: 'images', to: `${pkg_dir}/images` },
{ from: 'language', to: `${pkg_dir}/language` },
{ from: 'package.json', to: `${pkg_dir}/package.json` },
{ from: 'yarn.lock', to: `${pkg_dir}/yarn.lock` },
{
from: 'node_modules/@omega-edit/server/out',
to: `${pkg_dir}/node_modules/@omega-edit/server/out`,
},
{
from: 'node_modules/@vscode/webview-ui-toolkit',
to: `${pkg_dir}/node_modules/@vscode/webview-ui-toolkit`,
},
{
from: 'src/language/providers/intellisense/DFDLGeneralFormat.dfdl.xsd',
to: `${pkg_dir}/src/language/providers/intellisense/DFDLGeneralFormat.dfdl.xsd`,
},
{
from: 'src/launchWizard/script.js',
to: `${pkg_dir}/src/launchWizard/script.js`,
},
{ from: 'src/styles/styles.css', to: `${pkg_dir}/src/styles/styles.css` },
{ from: 'src/tdmlEditor/', to: `${pkg_dir}/src/tdmlEditor` },
{ from: 'dist/debuggers', to: `${pkg_dir}/dist/debuggers` },
]
return {
name: 'copy-patterns-plugin',
apply: 'build',
async buildStart(opts) {
;[
pkg_dir + '/dist',
pkg_dir + '/src/language',
pkg_dir + '/src/language/providers',
pkg_dir + '/src/language/providers/intellisense/',
pkg_dir + '/src/launchWizard',
pkg_dir + '/src/styles',
pkg_dir + '/src/tdmlEditor',
].forEach((folder) => {
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder, { recursive: true })
}
})
for (const { from, to } of patterns) {
fs.statSync(from).isFile()
? fs.copyFileSync(from, to)
: fs.cpSync(from, to, { recursive: true })
}
},
}
}
const shouldMinify = process.env.MINIFY === '1'
export default defineConfig(({ mode }) => {
return {
resolve: {
preserveSymlinks: true,
alias: {
...localModuleAliases,
},
extensions: ['.ts', '.js'],
},
build: {
sourcemap: true,
minify: shouldMinify ? 'esbuild' : false,
outDir: path.resolve(
__dirname,
mode == 'production' ? `${pkg_dir}/dist/ext` : 'dist/ext'
),
emptyOutDir: true,
rollupOptions: {
input: {
extension: path.resolve(__dirname, 'src/adapter/extension.ts'),
},
external: ['vscode', '@omega-edit/client', ...builtinModules, /^node:.*/],
output: {
entryFileNames: 'extension.js',
format: 'cjs',
exports: 'auto',
},
preserveEntrySignatures: 'strict',
},
target: 'node18',
},
plugins:
mode == 'production'
? [
copyDebuggerOutAfterBuild(),
copyToPkgDirPlugin(),
downloadAndExtractDefaultVersionOfDaffodil(mode),
]
: [copyDebuggerOutAfterBuild()],
}
})