Skip to content
This repository has been archived by the owner on Nov 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #158 from eyelidlessness/refactor/typescript-build
Browse files Browse the repository at this point in the history
Convert remainder of library to TypeScript, Vite build, include type checking in CI
  • Loading branch information
lognaturel committed Jan 17, 2023
2 parents 6193fab + d565cb0 commit 49bf726
Show file tree
Hide file tree
Showing 73 changed files with 894 additions and 13,626 deletions.
42 changes: 31 additions & 11 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"ecmaVersion": 2020
},
"settings": {
"import/extensions": [".js", ".ts"],
"import/extensions": [".ts"],
"import/parsers": {
"@typescript-eslint/parser": [".ts"]
},
Expand All @@ -46,18 +46,25 @@
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": ["vite.config.ts", "test/**/*.ts"],
"devDependencies": [
"app.js",
"app.ts",
"vite.config.ts",
"src/api.ts",
"test/**/*.ts"
],
"optionalDependencies": false,
"peerDependencies": false
}
],
"import/no-unresolved": [
"error",
{
"ignore": ["vitest/config"]
"ignore": ["vitest/config", ".*?raw"]
}
],
"import/order": "warn",
"import/prefer-default-export": "off",
"no-param-reassign": "warn",
"no-restricted-syntax": [
"warn",
Expand Down Expand Up @@ -85,17 +92,16 @@
}
},

{
"files": ["./**/*.js"],
"rules": {
"@typescript-eslint/no-var-requires": "off"
}
},

{
"files": ["./**/*.ts"],
"rules": {
"@typescript-eslint/no-unused-expressions": "off",
"no-useless-constructor": "off",
"@typescript-eslint/no-useless-constructor": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": "error",
"no-empty-function": "off",
"@typescript-eslint/no-empty-function": "error",

"import/extensions": [
"error",
"ignorePackages",
Expand All @@ -109,6 +115,20 @@
}
},

{
"files": ["./test/**/*.ts"],
"rules": {
"@typescript-eslint/no-unused-expressions": "off"
}
},

{
"files": ["./**/*.d.ts"],
"rules": {
"no-unused-vars": "off"
}
},

{
"files": ["./test/**/*.ts"],
"plugins": ["vitest"],
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/npmjs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ jobs:
- if: steps.cache.outputs.cache-hit != 'true'
run: npm ci
- run: npm test
- run: npm run build-docs
- if: github.event_name == 'release' && github.event.action == 'published' && matrix.node == '16'
run: npm publish
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ Thumbs.db
.nyc_output
test-coverage
coverage.shield.badge.md
dist
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

.nyc*
*/node_modules/*
dist/*
docs/*
test-coverage/*
49 changes: 24 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@

NodeJS library that transforms OpenRosa/ODK XForms into a format the Enketo understands. It works both as a library module, as well as a standalone app.

[Technical Documentation](https://enketo.github.io/enketo-transformer/)

### Prerequisites

1. Volta (optional, but recommended)
Expand All @@ -20,30 +18,32 @@ npm install enketo-transformer --save

### Use as module

```js
const transformer = require('enketo-transformer');
```ts
import { transform } from 'enketo-transformer';

const xform = fs.readFileSync('path/to/xform.xml');
const result = await transform({
// required string of XForm
xform: xform,

// optional string, to add theme if no theme is defined in the XForm
theme: 'sometheme',

// optional map, to replace jr://..../myfile.png URLs
media: {
'myfile.png': '/path/to/somefile.png',
'myfile.mp3': '/another/path/to/2.mp3',
},

// optional ability to disable markdown rendering (default is true)
markdown: false,

// optional preprocess function that transforms the XForm (as libXMLJs object) to
// e.g. correct incompatible XForm syntax before Enketo's transformation takes place
preprocess: (doc) => doc,
});

transformer
.transform({
// required string of XForm
xform: xform,
// optional string, to add theme if no theme is defined in the XForm
theme: 'sometheme',
// optional map, to replace jr://..../myfile.png URLs
media: {
'myfile.png': '/path/to/somefile.png',
'myfile.mp3': '/another/path/to/2.mp3',
},
// optional ability to disable markdown rendering (default is true)
markdown: false,
// optional preprocess function that transforms the XForm (as libXMLJs object) to
// e.g. correct incompatible XForm syntax before Enketo's transformation takes place
preprocess: (doc) => doc,
})
.then(function (result) {
// do something with result
});
// ... do something with result
```

### Install as app (web API)
Expand Down Expand Up @@ -129,7 +129,6 @@ Releases are done each time a dependent tool needs an `enketo-transformer` chang
- Run `npm audit fix --production` to apply most important fixes
1. Run `npm i`
1. Run `npm test`
1. Run `npm run build-docs`
1. Merge PR with all changes
1. Create GitHub release
1. Tag and publish the release
Expand Down
75 changes: 58 additions & 17 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,63 @@
const express = require('express');
// @ts-check

const app = express();
const bodyParser = require('body-parser');
const config = require('./config/config.json');
import { createServer } from 'vite';
import { VitePluginNode } from 'vite-plugin-node';
import {
config,
external,
resolvePath,
rootDir,
} from './config/build.shared.js';

for (const item in config) {
app.set(item, config[item]);
}
const appPath = resolvePath('./app.ts');

app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);
const init = async () => {
/** @type {import('vite').UserConfig} */
const baseOptions = {
mode: 'development',
build: {
rollupOptions: {
external,
},
},
optimizeDeps: {
disabled: true,
},
root: rootDir,
ssr: {
target: 'node',
},
};

require('./src/api')(app);
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,
},
}),
]);

app.listen(app.get('port'), () => {
console.warn(`enketo-transformer running on port ${app.get('port')}!`);
});
await Promise.all(servers.map((server) => server.listen()));

servers.forEach((server) => {
server.printUrls();
});
};

init();
21 changes: 21 additions & 0 deletions app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import bodyParser from 'body-parser';
import express from 'express';
import { config } from './config/build.shared';
import { api } from './src/api';

const app = express();

Object.entries(config).forEach(([key, value]) => {
app.set(key, value);
});

app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: true,
})
);

api(app);

export { app };
7 changes: 7 additions & 0 deletions config/build.shared.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export {
config,
external,
resolvePath,
readFile,
rootDir,
} from './build.shared';
42 changes: 42 additions & 0 deletions config/build.shared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// @ts-check

import fs from 'fs';
import { createRequire } from 'module';
import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';

const require = createRequire(import.meta.url);

export const config = require('./config.json');

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
*/
export const readFile = (path) => fs.readFileSync(resolvePath(path), 'utf-8');
Loading

0 comments on commit 49bf726

Please sign in to comment.