@salesforce/pwa-kit-react-sdk 3.0.0-preview.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +86 -0
  2. package/LICENSE +14 -0
  3. package/README.md +37 -0
  4. package/package.json +82 -0
  5. package/scripts/file-utils.js +80 -0
  6. package/scripts/file-utils.test.js +189 -0
  7. package/scripts/setup-jsdom.js +20 -0
  8. package/scripts/version.js +22 -0
  9. package/ssr/browser/main.js +122 -0
  10. package/ssr/browser/main.test.js +54 -0
  11. package/ssr/server/react-rendering.js +405 -0
  12. package/ssr/server/react-rendering.test.js +708 -0
  13. package/ssr/universal/compatibility.js +31 -0
  14. package/ssr/universal/components/_app/index.js +35 -0
  15. package/ssr/universal/components/_app/index.test.js +20 -0
  16. package/ssr/universal/components/_app-config/index.js +88 -0
  17. package/ssr/universal/components/_app-config/index.test.js +21 -0
  18. package/ssr/universal/components/_document/index.js +93 -0
  19. package/ssr/universal/components/_document/index.test.js +58 -0
  20. package/ssr/universal/components/_error/index.js +56 -0
  21. package/ssr/universal/components/_error/index.test.js +28 -0
  22. package/ssr/universal/components/app-error-boundary/index.js +115 -0
  23. package/ssr/universal/components/app-error-boundary/index.test.js +109 -0
  24. package/ssr/universal/components/fetch-strategy/index.js +42 -0
  25. package/ssr/universal/components/route-component/index.js +409 -0
  26. package/ssr/universal/components/route-component/index.test.js +375 -0
  27. package/ssr/universal/components/switch/index.js +63 -0
  28. package/ssr/universal/components/throw-404/index.js +37 -0
  29. package/ssr/universal/components/throw-404/index.test.js +26 -0
  30. package/ssr/universal/components/with-correlation-id/index.js +36 -0
  31. package/ssr/universal/components/with-legacy-get-props/index.js +86 -0
  32. package/ssr/universal/components/with-legacy-get-props/index.test.js +35 -0
  33. package/ssr/universal/components/with-react-query/index.js +103 -0
  34. package/ssr/universal/components/with-react-query/index.test.js +44 -0
  35. package/ssr/universal/contexts/index.js +71 -0
  36. package/ssr/universal/contexts/index.test.js +101 -0
  37. package/ssr/universal/errors.js +34 -0
  38. package/ssr/universal/errors.test.js +20 -0
  39. package/ssr/universal/events.js +40 -0
  40. package/ssr/universal/events.test.js +39 -0
  41. package/ssr/universal/hooks/index.js +52 -0
  42. package/ssr/universal/routes.js +16 -0
  43. package/ssr/universal/utils.client.test.js +46 -0
  44. package/ssr/universal/utils.js +60 -0
  45. package/ssr/universal/utils.server.test.js +24 -0
  46. package/utils/assets.js +120 -0
  47. package/utils/assets.test.js +106 -0
  48. package/utils/url.js +39 -0
  49. package/utils/url.test.js +47 -0
  50. package/utils/uuidv4.client.js +21 -0
  51. package/utils/uuidv4.client.test.js +27 -0
  52. package/utils/warnings.js +81 -0
  53. package/utils/warnings.test.js +48 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,86 @@
1
+ ## v3.0.0-preview.0 (May 31, 2023)
2
+ ## v3.0.0-dev (May 12, 2023)
3
+
4
+ - Remove usage of `device-context` due to deprecation of user agent string. [#1168](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1168)
5
+
6
+ - Remove usage of `device-context` due to deprecation of user agent string. [#1168](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1168)
7
+ - Upgrade React 18, React DOM 18, Remove Enzyme, add Testing library 14 [#1166](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1166)
8
+
9
+ ## v2.7.1 (May 11, 2023)
10
+
11
+ - Fix `multi-value` params being lost [#1150](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/1150)
12
+
13
+ ## v2.7.0 (Mar 03, 2023)
14
+
15
+ ## v2.6.0 (Jan 25, 2023)
16
+
17
+ ## v2.5.0 (Jan 05, 2023)
18
+
19
+ - Replace morgan stream to use console.log [#847](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/847)
20
+ - Do not use a proxy to call Einstein [#857](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/857)
21
+ - Reuse Server Correlation ID when Hydrating Error Pages [#846](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/846)
22
+
23
+ ## v2.4.0 (Dec 01, 2022)
24
+
25
+ - Fix `useServerContext` returning isServerSide=false when on server. [#782](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/782)
26
+ - Upgrade minimatch [#793](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/793)
27
+
28
+ ## v2.3.0 (Oct 27, 2022)
29
+
30
+ - Support `react-query` server-side data fetching. [#724](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/724)
31
+ - Add server-safe default configuration for `queryClientConfig` option. [#734](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/734)
32
+ - Add `useServerContext` hook with the `res` response object and the `isServerSide` flag. [#737](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/737)
33
+ - Handle `react-query` server-side errors. [#735](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/735)
34
+ - Fix internal build script. [#706](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/706)
35
+ - Add Correlation ID to SCAPI requests. [#728](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/728)
36
+
37
+ ## v2.2.0 (Aug 25, 2022)
38
+
39
+ ## v2.1.0 (Jul 05, 2022)
40
+
41
+ - Remove console logs from route component. [#651](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/651)
42
+
43
+ ## v2.0.0 (May 16, 2022)
44
+
45
+ - Drop node 12 support for [#589](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/589)
46
+ - Improve test coverage [#550](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/550)
47
+ - Remove lodash and bluebird. [#534](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/534)
48
+ - Support Multi-site implementation using dynamic config [#469](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/469)
49
+ - Support functions as default exports in the applications `routes.jsx` file. [#447](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/447)
50
+ - Serialize application configuration in the HTML during rendering process. [#447](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/447)
51
+ - Remove `create-hash-manifest.js` [#425](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/425)
52
+ - Fix upload bug with extending an options object [#419](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/419)
53
+
54
+ ## v1.5.0 (Mar 17, 2022)
55
+
56
+ - Add boolean flag `enableLegacyBodyParser` to `createApp` options. [#446](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/446)
57
+ - Add environment specific configuration support. [#421](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/421)
58
+ - Remove unused url-parse dependency [#411](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/411)
59
+ - Fix bug with extending an options object on upload.js script [#419](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/419)
60
+
61
+ ## v1.4.0 (Jan 27, 2022)
62
+
63
+ - Add `proxyKeepAliveAgent` ssr-server option. [#306](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/306)
64
+ - Add React 17 support [#278](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/278)
65
+ - Fix an error handling bug that could cause server to hang [#326](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/326)
66
+ - Add support for npm 7 and npm 8 [#302](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/302)
67
+
68
+ ## v1.3.0 (Jan 06, 2022)
69
+
70
+ - Add `__server_only` and `__pretty_print` server rendering flags aliases. [#250](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/250)
71
+ - Do not show stack trace in remote environment windowGlobals [#230](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/230/files)
72
+ - `createApp` takes a new option `enableLegacyRemoteProxying` which defaults to `true`. When set to `false`, local development proxying is disabled when running remotely. In future, local development proxying will _always_ be disabled when running remotely. [#205](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/205)
73
+ - Add `PwaKitConfigPlugin` webpack plugin. [#255](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/255)
74
+
75
+ ## v1.2.0 (Nov 18, 2021)
76
+
77
+ - Security package updates
78
+ - Upgrade `copy-webpack-plugin` to latest `^9.0.1` version. [#3191](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/181)
79
+
80
+ ## v1.1.0 (Sep 27, 2021)
81
+
82
+ - Update the bundle push command to remove legacy bundle upload preview URL from console output. [#81](https://github.com/SalesforceCommerceCloud/pwa-kit/pull/81)
83
+
84
+ ## v1.0.0 (Sep 08, 2021)
85
+
86
+ - PWA Kit General Avaliability and open source. 🎉
package/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2021, Salesforce.com, Inc.
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
11
+
12
+ 3. Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # The Progressive Web App (PWA) Kit SDK
2
+
3
+ [![NPM](https://nodei.co/npm/pwa-kit-react-sdk.png?downloads=true&stars=true)](https://nodei.co/npm/pwa-kit-react-sdk/) [![SalesforceCommerceCloud/pwa-kit/test](https://github.com/SalesforceCommerceCloud/pwa-kit/actions/workflows/test.yml/badge.svg)](https://github.com/SalesforceCommerceCloud/pwa-kit/actions/workflows/test.yml)
4
+
5
+ A library of components and utilities that supports the rendering pipeline for the Progressive Web App (PWA) Kit from Salesforce.
6
+
7
+ ## Requirements
8
+
9
+ - Node 16.11 or later
10
+ - npm 8 or later
11
+
12
+ ## Install Dependencies
13
+
14
+ ```bash
15
+ npm i
16
+ ```
17
+
18
+ ## Documentation
19
+
20
+ The full documentation for PWA Kit and Managed Runtime is hosted on the [Salesforce Developers](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/overview) portal.
21
+
22
+ ### Useful Links:
23
+
24
+ - [Get Started](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/getting-started.html)
25
+ - [Skills for Success](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/skills-for-success.html)
26
+ - [Set Up API Access](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/setting-up-api-access.html)
27
+ - [Configuration Options](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/configuration-options.html)
28
+ - [Proxy Requests](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/proxying-requests.html)
29
+ - [Push and Deploy Bundles](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/pushing-and-deploying-bundles.html)
30
+ - [The Retail React App](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/retail-react-app.html)
31
+ - [Rendering](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/rendering.html)
32
+ - [Routing](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/routing.html)
33
+ - [Phased Headless Rollouts](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/phased-headless-rollouts.html)
34
+ - [Launch Your Storefront](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/launching-your-storefront.html)
35
+
36
+ ## Support Policy
37
+ Security patches are provided for 24 months after the general availability of each major version of the SDK (1.0, 2.0, and so on).
package/package.json ADDED
@@ -0,0 +1,82 @@
1
+ {
2
+ "name": "@salesforce/pwa-kit-react-sdk",
3
+ "version": "3.0.0-preview.0",
4
+ "description": "A library that supports the isomorphic React rendering pipeline for Commerce Cloud Managed Runtime apps",
5
+ "homepage": "https://github.com/SalesforceCommerceCloud/pwa-kit/tree/develop/packages/pwa-kit-react-sdk#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/SalesforceCommerceCloud/pwa-kit/issues"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/SalesforceCommerceCloud/pwa-kit.git"
12
+ },
13
+ "license": "SEE LICENSE IN LICENSE",
14
+ "author": "cc-pwa-kit@salesforce.com",
15
+ "files": [
16
+ "CHANGELOG.md",
17
+ "LICENSE",
18
+ "scripts",
19
+ "ssr",
20
+ "utils"
21
+ ],
22
+ "scripts": {
23
+ "build": "cross-env NODE_ENV=production internal-lib-build build",
24
+ "build:watch": "nodemon --watch 'src/**' --exec 'npm run build'",
25
+ "format": "internal-lib-build format \"**/*.{js,jsx}\"",
26
+ "lint": "npm run lint:js",
27
+ "lint:fix": "npm run lint:js -- --fix",
28
+ "lint:js": "pwa-kit-dev lint \"**/*.{js,jsx}\"",
29
+ "prepare": "npm run build",
30
+ "test": "pwa-kit-dev test",
31
+ "test:inspect": "node --inspect-brk jest --runInBand",
32
+ "test:watch": "npm test -- --watch",
33
+ "version": "node ./scripts/version.js"
34
+ },
35
+ "dependencies": {
36
+ "@loadable/babel-plugin": "^5.15.3",
37
+ "@loadable/server": "^5.15.3",
38
+ "@loadable/webpack-plugin": "^5.15.2",
39
+ "@salesforce/pwa-kit-runtime": "3.0.0-preview.0",
40
+ "@tanstack/react-query": "^4.28.0",
41
+ "cross-env": "^5.2.1",
42
+ "event-emitter": "^0.3.5",
43
+ "hoist-non-react-statics": "^3.3.2",
44
+ "prop-types": "^15.8.1",
45
+ "react-ssr-prepass": "^1.5.0",
46
+ "react-uid": "^2.3.2",
47
+ "serialize-javascript": "^6.0.1",
48
+ "svg-sprite-loader": "^6.0.11"
49
+ },
50
+ "devDependencies": {
51
+ "@loadable/component": "^5.15.3",
52
+ "@salesforce/pwa-kit-dev": "3.0.0-preview.0",
53
+ "@testing-library/jest-dom": "^5.16.5",
54
+ "@testing-library/react": "^14.0.0",
55
+ "@testing-library/user-event": "^14.4.3",
56
+ "internal-lib-build": "3.0.0-preview.0",
57
+ "node-html-parser": "^3.3.6",
58
+ "nodemon": "^2.0.22",
59
+ "react": "^18.2.0",
60
+ "react-dom": "^18.2.0",
61
+ "react-helmet": "5.2.1",
62
+ "react-router-dom": "^5.3.4",
63
+ "regenerator-runtime": "^0.13.11",
64
+ "sinon": "^13.0.2",
65
+ "supertest": "^4.0.2"
66
+ },
67
+ "peerDependencies": {
68
+ "@loadable/component": "^5.15.0",
69
+ "react": "^18",
70
+ "react-dom": "^18",
71
+ "react-helmet": "6",
72
+ "react-router-dom": "^5.1.2"
73
+ },
74
+ "engines": {
75
+ "node": "^16.11.0 || ^18.0.0",
76
+ "npm": "^8.0.0 || ^9.0.0"
77
+ },
78
+ "publishConfig": {
79
+ "directory": "dist"
80
+ },
81
+ "gitHead": "a9f820893b7714244a0af509a5aefecc1344153c"
82
+ }
@@ -0,0 +1,80 @@
1
+ /*
2
+ * Copyright (c) 2022, Salesforce, Inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+ /* eslint-disable @typescript-eslint/no-var-requires */
8
+
9
+ const fs = require('fs')
10
+
11
+ // TODO: Update tests so that fs.promises can be used directly
12
+ const promisify = require('util').promisify
13
+ const readFileAsync = promisify(fs.readFile)
14
+ const writeFileAsync = promisify(fs.writeFile)
15
+ const statAsync = promisify(fs.stat)
16
+ const mkdirAsync = promisify(fs.mkdir)
17
+ const readdirAsync = promisify(fs.readdir)
18
+
19
+ const readFile = (path) => readFileAsync(path, 'utf8')
20
+ const writeFile = (path, contents) => writeFileAsync(path, contents, 'utf8')
21
+
22
+ const writeToPath = (path) => (contents) => writeFile(path, contents)
23
+
24
+ const mkdirIfNonexistent = (dirname) => statAsync(dirname).catch(() => mkdirAsync(dirname))
25
+
26
+ const existsSync = (path) => {
27
+ try {
28
+ fs.statSync(path)
29
+ return true
30
+ } catch (e) {
31
+ return false
32
+ }
33
+ }
34
+
35
+ const filterOnStat = (pathBuilder, statCondition) => async (items) => {
36
+ const promises = items.map(async (item) => {
37
+ try {
38
+ const stats = await statAsync(pathBuilder(item))
39
+ return statCondition(stats) ? item : null
40
+ } catch (_) {
41
+ // Ignoring the error because we only care about valid paths
42
+ return null
43
+ }
44
+ })
45
+ const results = await Promise.all(promises)
46
+ return results.filter((item) => item != null)
47
+ }
48
+
49
+ const filterDirectories = (pathBuilder) => filterOnStat(pathBuilder, (stats) => stats.isDirectory())
50
+
51
+ const filterFiles = (pathBuilder) => filterOnStat(pathBuilder, (stats) => stats.isFile())
52
+
53
+ const jsonRead = (path) => {
54
+ return readFile(path).then((text) => JSON.parse(text))
55
+ }
56
+
57
+ const jsonWrite = (path) => (contents) => {
58
+ return writeFile(path, JSON.stringify(contents, null, 2))
59
+ }
60
+
61
+ module.exports = {
62
+ // Just passing through
63
+ createWriteStream: fs.createWriteStream,
64
+
65
+ // Async fs functions
66
+ readdirAsync,
67
+ statAsync,
68
+ readFileAsync,
69
+
70
+ // Local utilities
71
+ readFile,
72
+ writeFile,
73
+ writeToPath,
74
+ mkdirIfNonexistent,
75
+ existsSync,
76
+ filterDirectories,
77
+ filterFiles,
78
+ jsonRead,
79
+ jsonWrite
80
+ }
@@ -0,0 +1,189 @@
1
+ /*
2
+ * Copyright (c) 2021, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+ /* eslint-disable @typescript-eslint/no-var-requires */
8
+
9
+ jest.mock('fs')
10
+ const fs = require('fs')
11
+
12
+ const fileUtils = require('./file-utils')
13
+
14
+ const successCallbackAdapter =
15
+ (value = true) =>
16
+ (...args) => {
17
+ args[args.length - 1](null, value)
18
+ }
19
+
20
+ const failureCallbackAdapter =
21
+ (value = {}) =>
22
+ (...args) => {
23
+ args[args.length - 1](value)
24
+ }
25
+
26
+ const argsIgnoringCallback = (mock, index = 0) => mock.mock.calls[index].slice(0, -1)
27
+
28
+ beforeEach(() => {
29
+ jest.resetAllMocks()
30
+ })
31
+
32
+ test('readFile reads as utf8', () => {
33
+ fs.readFile.mockImplementation(successCallbackAdapter())
34
+
35
+ return fileUtils.readFile('test.dat').then(() => {
36
+ expect(fs.readFile).toHaveBeenCalled()
37
+ expect(fs.readFile.mock.calls[0].slice(0, -1)).toEqual(['test.dat', 'utf8'])
38
+ })
39
+ })
40
+
41
+ test('writeFile writes as utf8', () => {
42
+ fs.writeFile.mockImplementation(successCallbackAdapter())
43
+
44
+ return fileUtils.writeFile('myfile.json', '{"test": true, "json": "JSON"}').then(() => {
45
+ expect(fs.writeFile.mock.calls).toHaveLength(1)
46
+ expect(fs.writeFile.mock.calls[0].slice(0, -1)).toEqual([
47
+ 'myfile.json',
48
+ '{"test": true, "json": "JSON"}',
49
+ 'utf8'
50
+ ])
51
+ })
52
+ })
53
+
54
+ test('writeToPath returns a function that writes to a given path', () => {
55
+ fs.writeFile.mockImplementation(successCallbackAdapter())
56
+
57
+ const writer = fileUtils.writeToPath('test/summary.dat')
58
+
59
+ expect(typeof writer).toBe('function')
60
+ expect(fs.writeFile).not.toHaveBeenCalled()
61
+
62
+ return writer('ABC 123').then(() => {
63
+ expect(fs.writeFile).toHaveBeenCalled()
64
+ expect(fs.writeFile.mock.calls[0].slice(0, -1)).toEqual([
65
+ 'test/summary.dat',
66
+ 'ABC 123',
67
+ 'utf8'
68
+ ])
69
+ })
70
+ })
71
+
72
+ test('mkdirIfNonexistent does not make a directory if it exists', () => {
73
+ fs.stat.mockImplementation(successCallbackAdapter({test: true}))
74
+
75
+ return fileUtils.mkdirIfNonexistent('testdir').then((result) => {
76
+ expect(fs.stat).toHaveBeenCalledTimes(1)
77
+ expect(argsIgnoringCallback(fs.stat)).toEqual(['testdir'])
78
+ expect(fs.mkdir).not.toHaveBeenCalled()
79
+ expect(result.test).toBe(true)
80
+ })
81
+ })
82
+
83
+ test("mkdirIfNonexistent makes a directory if it doesn't exist", () => {
84
+ fs.stat.mockImplementation(failureCallbackAdapter('test'))
85
+ fs.mkdir.mockImplementation(successCallbackAdapter())
86
+
87
+ return fileUtils.mkdirIfNonexistent('testdir').then(() => {
88
+ expect(fs.stat).toHaveBeenCalled()
89
+ expect(argsIgnoringCallback(fs.stat)).toEqual(['testdir'])
90
+ expect(fs.mkdir).toHaveBeenCalled()
91
+ expect(argsIgnoringCallback(fs.mkdir)).toEqual(['testdir'])
92
+ })
93
+ })
94
+
95
+ test('existsSync calls statSync and returns true if it succeeds', () => {
96
+ fs.statSync.mockReturnValueOnce(true)
97
+ expect(fileUtils.existsSync('test.dat')).toBe(true)
98
+ expect(fs.statSync.mock.calls).toHaveLength(1)
99
+ expect(fs.statSync.mock.calls[0][0]).toBe('test.dat')
100
+ })
101
+
102
+ test('existsSync returns false if statSync throws', () => {
103
+ fs.statSync.mockImplementation(() => {
104
+ throw new Error('test')
105
+ })
106
+
107
+ expect(fileUtils.existsSync('test.dat')).toBe(false)
108
+ })
109
+
110
+ test('filterDirectories returns the names that are directories after passing through the pathBuilder', () => {
111
+ const dirList = ['a', 'c', 'r']
112
+ const itemList = ['a', 'b', 'c', 'r', 's', 't']
113
+
114
+ fs.stat.mockImplementation((fn, callback) => {
115
+ if (dirList.indexOf(fn) !== -1) {
116
+ callback(null, {isDirectory: () => true})
117
+ } else if (fn === 's') {
118
+ callback({err: true})
119
+ } else {
120
+ callback(null, {isDirectory: () => false})
121
+ }
122
+ })
123
+
124
+ const pathBuilder = jest.fn().mockImplementation((x) => x)
125
+
126
+ return fileUtils
127
+ .filterDirectories(pathBuilder)(itemList)
128
+ .then((result) => {
129
+ expect(fs.stat.mock.calls).toHaveLength(itemList.length)
130
+ expect(pathBuilder.mock.calls).toHaveLength(itemList.length)
131
+ itemList.forEach((item) => {
132
+ expect(pathBuilder).toHaveBeenCalledWith(item)
133
+ })
134
+
135
+ expect(result).toEqual(dirList)
136
+ })
137
+ })
138
+
139
+ test('filterFiles returns the names that are directories after passing through the pathBuilder', () => {
140
+ const fileList = ['b', 't']
141
+ const itemList = ['a', 'b', 'c', 'r', 's', 't']
142
+
143
+ fs.stat.mockImplementation((fn, callback) => {
144
+ if (fileList.indexOf(fn) !== -1) {
145
+ callback(null, {isFile: () => true})
146
+ } else if (fn === 's') {
147
+ callback({err: true})
148
+ } else {
149
+ callback(null, {isFile: () => false})
150
+ }
151
+ })
152
+
153
+ const pathBuilder = jest.fn().mockImplementation((x) => x)
154
+
155
+ return fileUtils
156
+ .filterFiles(pathBuilder)(itemList)
157
+ .then((result) => {
158
+ expect(fs.stat.mock.calls).toHaveLength(itemList.length)
159
+ expect(pathBuilder.mock.calls).toHaveLength(itemList.length)
160
+ itemList.forEach((item) => {
161
+ expect(pathBuilder).toHaveBeenCalledWith(item)
162
+ })
163
+
164
+ expect(result).toEqual(fileList)
165
+ })
166
+ })
167
+
168
+ test('jsonRead reads JSON from a file', () => {
169
+ fs.readFile.mockImplementation(successCallbackAdapter('{"test": true}'))
170
+
171
+ return fileUtils.jsonRead('test.json').then((result) => {
172
+ expect(fs.readFile).toHaveBeenCalled()
173
+ expect(fs.readFile.mock.calls[0][0]).toBe('test.json')
174
+
175
+ expect(result).toEqual({test: true})
176
+ })
177
+ })
178
+
179
+ test('jsonWrite writes JSON to a file', () => {
180
+ fs.writeFile.mockImplementation(successCallbackAdapter())
181
+
182
+ return fileUtils
183
+ .jsonWrite('test.json')({test: true})
184
+ .then(() => {
185
+ expect(fs.writeFile).toHaveBeenCalled()
186
+ expect(fs.writeFile.mock.calls[0][0]).toBe('test.json')
187
+ expect(fs.writeFile.mock.calls[0][1]).toBe('{\n "test": true\n}')
188
+ })
189
+ })
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Copyright (c) 2021, salesforce.com, inc.
3
+ * All rights reserved.
4
+ * SPDX-License-Identifier: BSD-3-Clause
5
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6
+ */
7
+
8
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
9
+ global.document = require('jsdom').jsdom('<body></body>')
10
+ global.window = document.defaultView
11
+ global.window.matchMedia =
12
+ global.window.matchMedia ||
13
+ function () {
14
+ return {
15
+ matches: false,
16
+ addListener: () => {},
17
+ removeListener: () => {}
18
+ }
19
+ }
20
+ global.navigator = window.navigator
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Copyright (c) 2023, Salesforce, Inc.
4
+ * All rights reserved.
5
+ * SPDX-License-Identifier: BSD-3-Clause
6
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
7
+ */
8
+ /* eslint-disable @typescript-eslint/no-var-requires */
9
+ // Update Change Log heading
10
+ const pkg = require('../package.json')
11
+ const path = require('path')
12
+ const os = require('os')
13
+ const fs = require('fs')
14
+
15
+ const date = new Date().toString().split(' ').slice(1, 4)
16
+ const heading = `## v${pkg.version} (${date[0]} ${date[1]}, ${date[2]})\n`
17
+
18
+ const changelog = path.resolve(os.tmpdir(), 'CHANGELOG.md')
19
+
20
+ fs.writeFileSync(changelog, heading, 'utf8')
21
+ fs.appendFileSync(changelog, fs.readFileSync('CHANGELOG.md'), 'utf8')
22
+ fs.copyFileSync(changelog, 'CHANGELOG.md')
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.start = exports.registerServiceWorker = exports.OuterApp = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _client = require("react-dom/client");
9
+ var _reactRouterDom = require("react-router-dom");
10
+ var _contexts = require("../universal/contexts");
11
+ var _app = _interopRequireDefault(require("../universal/components/_app"));
12
+ var _compatibility = require("../universal/compatibility");
13
+ var _switch = _interopRequireDefault(require("../universal/components/switch"));
14
+ var _routeComponent = require("../universal/components/route-component");
15
+ var _component = require("@loadable/component");
16
+ var _uuidv = require("../../utils/uuidv4.client");
17
+ var _propTypes = _interopRequireDefault(require("prop-types"));
18
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
20
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
21
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } /*
22
+ * Copyright (c) 2021, salesforce.com, inc.
23
+ * All rights reserved.
24
+ * SPDX-License-Identifier: BSD-3-Clause
25
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/BSD-3-Clause
26
+ */ /* global __webpack_require__ */
27
+ /* istanbul ignore next */
28
+ const registerServiceWorker = url => {
29
+ return Promise.resolve().then(() => {
30
+ if ('serviceWorker' in navigator) {
31
+ return Promise.resolve().then(() => new Promise(resolve => window.addEventListener('load', resolve))).then(() => navigator.serviceWorker.register(url)).then(registration => console.log(`ServiceWorker registration successful with scope: ${registration.scope}`)).catch(err => console.log('ServiceWorker registration failed: ', err));
32
+ }
33
+ });
34
+ };
35
+ exports.registerServiceWorker = registerServiceWorker;
36
+ const OuterApp = ({
37
+ routes,
38
+ error,
39
+ WrappedApp,
40
+ locals,
41
+ onHydrate
42
+ }) => {
43
+ const AppConfig = (0, _compatibility.getAppConfig)();
44
+ const isInitialPageRef = (0, _react.useRef)(true);
45
+ return /*#__PURE__*/_react.default.createElement(_contexts.ServerContext.Provider, {
46
+ value: {}
47
+ }, /*#__PURE__*/_react.default.createElement(_reactRouterDom.BrowserRouter, {
48
+ ref: onHydrate
49
+ }, /*#__PURE__*/_react.default.createElement(_contexts.CorrelationIdProvider, {
50
+ correlationId: () => {
51
+ // If we are hydrating an error page use the server correlation id.
52
+ if (isInitialPageRef.current && window.__ERROR__) {
53
+ isInitialPageRef.current = false;
54
+ return window.__INITIAL_CORRELATION_ID__;
55
+ }
56
+ return (0, _uuidv.uuidv4)();
57
+ }
58
+ }, /*#__PURE__*/_react.default.createElement(AppConfig, {
59
+ locals: locals
60
+ }, /*#__PURE__*/_react.default.createElement(_switch.default, {
61
+ error: error,
62
+ appState: window.__PRELOADED_STATE__,
63
+ routes: routes,
64
+ App: WrappedApp
65
+ })))));
66
+ };
67
+ exports.OuterApp = OuterApp;
68
+ OuterApp.propTypes = {
69
+ routes: _propTypes.default.array.isRequired,
70
+ error: _propTypes.default.object,
71
+ WrappedApp: _propTypes.default.func.isRequired,
72
+ locals: _propTypes.default.object,
73
+ onHydrate: _propTypes.default.func
74
+ };
75
+ /* istanbul ignore next */
76
+ const start = () => {
77
+ const AppConfig = (0, _compatibility.getAppConfig)();
78
+ const rootEl = document.getElementsByClassName('react-target')[0];
79
+ const data = JSON.parse(document.getElementById('mobify-data').innerHTML);
80
+
81
+ // Set all globals sent from the server on the window object.
82
+ Object.entries(data).forEach(([key, value]) => {
83
+ window[key] = value;
84
+ });
85
+
86
+ // Tell webpack how to find javascript files
87
+ Object.defineProperty(__webpack_require__, 'p', {
88
+ get: () => window.Progressive.buildOrigin
89
+ });
90
+
91
+ // On the browser we don't have request.locals, so we just provide an empty
92
+ // object that exists for the lifetime of the app. AppConfig components can use
93
+ // this to set up, eg. Redux stores.
94
+ const locals = {};
95
+
96
+ // AppConfig.restore *must* come before getRoutes()
97
+ AppConfig.restore(locals, window.__PRELOADED_STATE__.__STATE_MANAGEMENT_LIBRARY);
98
+
99
+ // We need to tell the routeComponent HOC when the app is hydrating in order to
100
+ // prevent pages from re-fetching data on the first client-side render. The
101
+ // reason we do this is that we expect a render to have taken place
102
+ // on the server already. That server-side render already called getProps()
103
+ // and froze the application state as a JSON blob on the page.
104
+ //
105
+ // This is VERY fiddly – don't go crazy with window.__HYDRATING__. You have
106
+ // been warned.
107
+ window.__HYDRATING__ = true;
108
+ const props = {
109
+ error: window.__ERROR__,
110
+ locals: locals,
111
+ routes: (0, _routeComponent.getRoutes)(locals),
112
+ WrappedApp: (0, _routeComponent.routeComponent)(_app.default, false, locals)
113
+ };
114
+ return Promise.resolve().then(() => new Promise(resolve => (0, _component.loadableReady)(resolve))).then(() => {
115
+ (0, _client.hydrateRoot)(rootEl, /*#__PURE__*/_react.default.createElement(OuterApp, _extends({}, props, {
116
+ onHydrate: () => {
117
+ window.__HYDRATING__ = false;
118
+ }
119
+ })));
120
+ });
121
+ };
122
+ exports.start = start;