1
0
mirror of https://github.com/sasjs/adapter.git synced 2025-12-10 08:54:35 +00:00

fix: new axios requires form data content type, es6 strict issues with iterations

This commit is contained in:
2025-03-07 10:36:43 +01:00
parent 008a9b4ca5
commit 4fb0b96f11
12 changed files with 478 additions and 374 deletions

View File

@@ -0,0 +1,15 @@
// craco.config.js
// We use craco instead of react-scripts so we can override webpack config, to include source maps
// so we can debug @sasjs/adapter easier when tests fail
module.exports = {
webpack: {
configure: (webpackConfig, { env }) => {
// Disable optimizations in both development and production
webpackConfig.optimization.minimize = false;
webpackConfig.optimization.minimizer = [];
webpackConfig.optimization.concatenateModules = false;
webpackConfig.optimization.splitChunks = { cacheGroups: { default: false } };
return webpackConfig;
}
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@
},
"scripts": {
"start": "NODE_OPTIONS=--openssl-legacy-provider react-scripts start",
"build": "react-scripts build",
"build": "NODE_OPTIONS=--openssl-legacy-provider craco build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"update:adapter": "cd .. && npm run package:lib && cd sasjs-tests && npm i ../build/sasjs-adapter-5.0.0.tgz",
@@ -43,6 +43,8 @@
]
},
"devDependencies": {
"node-sass": "9.0.0"
"@craco/craco": "6.4.3",
"node-sass": "9.0.0",
"source-map-loader": "0.2.4"
}
}

View File

@@ -134,8 +134,19 @@ export const specialCaseTests = (adapter: SASjs): TestSuite => ({
return adapter.request('common/sendArr', moreSpecialCharData)
},
assertion: (res: any) => {
// If sas session is latin9 we can't process the special characters
if (res.SYSENCODING === 'latin9') return true
// If sas session is `latin9` or `wlatin1` we can't process the special characters,
// But it can happen that response is broken JSON, so we first need to check if
// it's object and then check accordingly
if (typeof res === 'object') {
// Valid JSON response
if (res.SYSENCODING === 'latin9' || res.SYSENCODING === 'wlatin1')
return true
} else {
// Since we got string response (broken JSON), we need to check with regex
const regex = /"SYSENCODING"\s*:\s*"(?:wlatin1|latin9)"/
if (regex.test(res)) return true
}
return (
res.table1[0][0] === moreSpecialCharData.table1[0].speech0 &&

View File

@@ -6,6 +6,8 @@
"dom.iterable",
"esnext"
],
"sourceMap": true,
"inlineSources": true,
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,

View File

@@ -73,8 +73,10 @@ export class SasjsJobExecutor extends BaseJobExecutor {
/* The NodeFormData object does not set the request header - so, set it */
const contentType =
formData instanceof NodeFormData && typeof FormData === 'undefined'
? `multipart/form-data; boundary=${formData.getBoundary()}`
: undefined
? `multipart/form-data; boundary=${
formData.getHeaders()['content-type']
}`
: 'multipart/form-data'
const requestPromise = new Promise((resolve, reject) => {
this.requestClient!.post(

View File

@@ -150,8 +150,10 @@ export class WebJobExecutor extends BaseJobExecutor {
/* The NodeFormData object does not set the request header - so, set it */
const contentType =
formData instanceof NodeFormData && typeof FormData === 'undefined'
? `multipart/form-data; boundary=${formData.getBoundary()}`
: undefined
? `multipart/form-data; boundary=${
formData.getHeaders()['content-type']
}`
: 'multipart/form-data'
const requestPromise = new Promise((resolve, reject) => {
this.requestClient!.post(

View File

@@ -191,6 +191,13 @@ export class RequestClient implements HttpClient {
})
}
/**
* @param contentType Newer version of Axios is more strict so if you don't
* set the contentType to `form data` while sending a FormData object
* application/json will be used by default, axios wont treat it as FormData.
* Instead, it serializes data as JSON—resulting in a payload like
* {"sometable":{}} and we lose the multipart/form-data formatting.
*/
public async post<T>(
url: string,
data: any,

View File

@@ -1,5 +1,5 @@
import { isNode } from './'
import NodeFormData from 'form-data'
export const getFormData = () =>
export const getFormData = (): NodeFormData | FormData =>
isNode() ? new NodeFormData() : new FormData()

View File

@@ -52,19 +52,22 @@ export const validateInput = (
}
}
for (const item of data[key]) {
if (getType(item) !== 'object') {
return {
status: false,
msg: `Table ${key} contains invalid structure. ${MORE_INFO}`
}
} else {
const attributes = Object.keys(item)
for (const attribute of attributes) {
if (item[attribute] === undefined) {
return {
status: false,
msg: `A row in table ${key} contains invalid value. Can't assign undefined to ${attribute}.`
// ES6 is stricter so we had to include the check for the array
if (Array.isArray(data[key])) {
for (const item of data[key]) {
if (getType(item) !== 'object') {
return {
status: false,
msg: `Table ${key} contains invalid structure. ${MORE_INFO}`
}
} else {
const attributes = Object.keys(item)
for (const attribute of attributes) {
if (item[attribute] === undefined) {
return {
status: false,
msg: `A row in table ${key} contains invalid value. Can't assign undefined to ${attribute}.`
}
}
}
}

View File

@@ -8,6 +8,7 @@
"esModuleInterop": true,
"strict": true,
"sourceMap": true,
"inlineSources": true,
"typeRoots": ["./node_modules/@types", "./src/types/system"]
},
"include": ["src"],

View File

@@ -13,12 +13,12 @@ const defaultPlugins = [
]
const optimization = {
minimize: true,
minimize: false,
minimizer: [
new terserPlugin({
parallel: true,
terserOptions: {}
})
// new terserPlugin({
// parallel: true,
// terserOptions: {}
// })
]
}
@@ -44,6 +44,7 @@ const browserConfig = {
},
mode: 'production',
optimization: optimization,
devtool: 'inline-source-map',
module: {
rules: [
{