From 2a41ca08cfb0936876555681544736c8fb8b4812 Mon Sep 17 00:00:00 2001 From: eyelidlessness Date: Fri, 13 Jan 2023 11:27:43 -0800 Subject: [PATCH] Fix build, a few errors found in core and express --- .eslintrc.json | 2 +- app.js | 63 ++++++++++++++++++++++++++++++++++++++++++ config/build.shared.js | 39 ++++++++++++++++++++++++++ src/transformer.ts | 25 +++++++++-------- vite.config.ts | 26 ++++++++++------- 5 files changed, 132 insertions(+), 23 deletions(-) create mode 100644 app.js create mode 100644 config/build.shared.js diff --git a/.eslintrc.json b/.eslintrc.json index 36e2642..20a64c3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -59,7 +59,7 @@ "import/no-unresolved": [ "error", { - "ignore": ["vitest/config"] + "ignore": ["vitest/config", ".*?raw"] } ], "import/order": "warn", diff --git a/app.js b/app.js new file mode 100644 index 0000000..385f0b3 --- /dev/null +++ b/app.js @@ -0,0 +1,63 @@ +// @ts-check + +import { createServer } from 'vite'; +import { VitePluginNode } from 'vite-plugin-node'; +import { + config, + external, + resolvePath, + rootDir, +} from './config/build.shared.js'; + +const appPath = resolvePath('./app.ts'); + +const init = async () => { + /** @type {import('vite').UserConfig} */ + const baseOptions = { + mode: 'development', + build: { + rollupOptions: { + external, + }, + }, + optimizeDeps: { + disabled: true, + }, + root: rootDir, + ssr: { + target: 'node', + }, + }; + + const servers = await Promise.all([ + createServer({ + ...baseOptions, + configFile: false, + plugins: VitePluginNode({ + adapter: 'express', + appPath, + exportName: 'app', + tsCompiler: 'esbuild', + }), + server: { + port: config.port, + }, + }), + createServer({ + ...baseOptions, + configFile: false, + publicDir: resolvePath('./test/forms'), + server: { + port: 8081, + }, + }), + ]); + + await Promise.all(servers.map((server) => server.listen())); + + servers.forEach((server) => { + server.printUrls(); + }); +}; + +init(); diff --git a/config/build.shared.js b/config/build.shared.js new file mode 100644 index 0000000..a112fc1 --- /dev/null +++ b/config/build.shared.js @@ -0,0 +1,39 @@ +// @ts-check + +import fs from 'fs'; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; + +export const external = [ + 'body-parser', + 'crypto', + 'css.escape', + 'express', + 'fs', + 'language-tags', + 'libxslt', + 'node1-libxmljsmt-myh', + 'path', + 'string-direction', + 'undici', + 'url', + 'vite-node', + 'vite', +]; + +export const rootDir = dirname(fileURLToPath(import.meta.url)).replace( + /(\/enketo-transformer)(\/.*$)/, + '$1' +); + +/** + * @param {string} path + */ +export const resolvePath = (path) => resolve(rootDir, path); + +/** + * @param {string} path + */ +const readFile = (path) => fs.readFileSync(resolvePath(path), 'utf-8'); + +export const config = JSON.parse(readFile('./config/config.json')); diff --git a/src/transformer.ts b/src/transformer.ts index cddb5cd..e11c458 100644 --- a/src/transformer.ts +++ b/src/transformer.ts @@ -1,4 +1,3 @@ -import fs from 'fs'; import crypto from 'crypto'; import libxslt from 'libxslt'; import type { @@ -6,21 +5,14 @@ import type { DocumentFragment as XMLJSDocumentFragment, } from 'libxmljs'; import pkg from '../package.json'; +import xslForm from './xsl/openrosa2html5form.xsl?raw'; +import xslModel from './xsl/openrosa2xmlmodel.xsl?raw'; import language from './language'; import markdown from './markdown'; import { escapeURLPath, getMediaPath } from './url'; const { libxmljs } = libxslt; -const getXSL = (fileName: string) => { - const { pathname } = new URL(`./xsl/${fileName}`, import.meta.url); - - return fs.readFileSync(pathname, 'utf8'); -}; - -const xslForm = getXSL('openrosa2html5form.xsl'); -const xslModel = getXSL('openrosa2xmlmodel.xsl'); - export const NAMESPACES = { xmlns: 'http://www.w3.org/2002/xforms', orx: 'http://openrosa.org/xforms', @@ -103,12 +95,19 @@ export const transform = (survey: Survey): Promise => { const model = docToString(xmlDoc); - return { + // @ts-expect-error - This fails because `xform` is not optional, but this is API-consistent behavior. + delete survey.xform; + delete survey.media; + delete survey.preprocess; + delete survey.markdown; + delete survey.openclinica; + + return Object.assign(survey, { form, model, languageMap, transformerVersion: PACKAGE_VESION, - }; + }); }); }; @@ -515,6 +514,8 @@ const PACKAGE_VESION = pkg.version; const VERSION = md5(xslForm + xslModel + PACKAGE_VESION); +export { VERSION as version }; + export const sheets = { xslForm, xslModel, diff --git a/vite.config.ts b/vite.config.ts index 5e1bd70..174ead2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,7 +1,7 @@ import { resolve } from 'path'; import { defineConfig } from 'vitest/config'; -import { VitePluginNode } from 'vite-plugin-node'; import config from './config/config.json'; +import { external } from './config/build.shared'; export default defineConfig({ assetsInclude: ['**/*.xml', '**/*.xsl'], @@ -12,19 +12,25 @@ export default defineConfig({ }, minify: false, outDir: 'dist', + rollupOptions: { + external, + output: { + // This suppresses a warning for modules with both named and + // default exporrs when building for CommonJS (UMD in our + // current build). It's safe to suppress this warning because we + // have explicit tests ensuring both the default and named + // exports are consistent with the existing public API. + exports: 'named', + }, + }, sourcemap: true, }, esbuild: { sourcemap: 'inline', }, - plugins: [ - ...VitePluginNode({ - adapter: 'express', - appPath: './app.ts', - exportName: 'app', - tsCompiler: 'esbuild', - }), - ], + optimizeDeps: { + disabled: true, + }, server: { port: config.port, }, @@ -50,6 +56,6 @@ export default defineConfig({ globals: true, include: ['test/**/*.spec.ts'], reporters: 'verbose', - sequence: { shuffle: true }, + sequence: { shuffle: false }, }, });