Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into fix/allow-latest-tag
Browse files Browse the repository at this point in the history
  • Loading branch information
agorskiy12 authored Mar 22, 2024
2 parents 9543edb + 05c80cd commit 61edf75
Show file tree
Hide file tree
Showing 17 changed files with 319 additions and 45 deletions.
11 changes: 11 additions & 0 deletions packages/one-app-bundler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [7.0.2](https://github.com/americanexpress/one-app-cli/compare/@americanexpress/[email protected]...@americanexpress/[email protected]) (2024-03-20)


### Bug Fixes

* **appConfig:** restore check to app config ([08f62d2](https://github.com/americanexpress/one-app-cli/commit/08f62d2e8c2eadb4a9751ffd7ac5c51553972e8e))





## [7.0.1](https://github.com/americanexpress/one-app-cli/compare/@americanexpress/[email protected]...@americanexpress/[email protected]) (2024-03-12)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ testing `on import` functionality needs 'require' in every tests */
jest.mock('read-package-up', () => ({ readPackageUpSync: jest.fn(() => ({ pkg: {} })) }));
const consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => 0);

jest.mock('@americanexpress/one-app-dev-bundler', () => {});

describe('getConfigOptions', () => {
let readPkgUp;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`webpack/one-amex.base should add loader options plugin in production 1`] = `
Array [
RestrictRuntimeSymbols {},
EnvironmentPlugin {
"defaultValues": Object {},
"keys": Array [
Expand All @@ -22,6 +23,7 @@ Array [

exports[`webpack/one-amex.base should only include the EnvironmentPlugin in development 1`] = `
Array [
RestrictRuntimeSymbols {},
EnvironmentPlugin {
"defaultValues": Object {},
"keys": Array [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* Copyright 2024 American Express Travel Related Services Company, Inc.
*
* Licensed 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 fs from 'node:fs';
import { validateAppConfig } from '@americanexpress/one-app-dev-bundler';
import RestrictRuntimeSymbols from '../../../webpack/plugins/restrict-runtime-symbols.js';

jest.mock('@americanexpress/one-app-dev-bundler', () => ({
validateAppConfig: jest.fn(() => []),
}));

jest.mock('node:fs', () => ({
...jest.requireActual('node:fs'),
readFileSync: jest.fn(() => ''),
}));

describe('RestrictRuntimeSymbols', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should Register an assetEmitted tap hook', () => {
const plugin = new RestrictRuntimeSymbols();

const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn(),
},
},
};

plugin.apply(mockCompiler);

expect(mockCompiler.hooks.assetEmitted.tap).toHaveBeenCalledTimes(1);
expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});

it('The registered function should not throw with a file containing no problems', () => {
const plugin = new RestrictRuntimeSymbols();

let registeredFn;
const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn((_, fn) => {
registeredFn = fn;
}),
},
},
};

fs.readFileSync.mockImplementationOnce(() => 'console.log(`no problems`)');

plugin.apply(mockCompiler);

expect(registeredFn).not.toBe(undefined);

expect(() => registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.node.js' })).not.toThrow();
expect(() => registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.browser.js' })).not.toThrow();

expect(fs.readFileSync).toHaveBeenCalledTimes(2);

expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});

it('The registered function should throw if `create-react-class` is used in node bundles', () => {
const plugin = new RestrictRuntimeSymbols();

let registeredFn;
const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn((_, fn) => {
registeredFn = fn;
}),
},
},
};

fs.readFileSync.mockImplementationOnce(() => 'console.log(`create-react-class`)');

plugin.apply(mockCompiler);

expect(registeredFn).not.toBe(undefined);

expect(() => registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.node.js' })).toThrow('`create-react-class` is restricted from being used');

expect(fs.readFileSync).toHaveBeenCalledTimes(1);

expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});

it('The registered function should throw if `create-react-class` is used in browser bundles', () => {
const plugin = new RestrictRuntimeSymbols();

let registeredFn;
const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn((_, fn) => {
registeredFn = fn;
}),
},
},
};

fs.readFileSync.mockImplementationOnce(() => 'console.log(`create-react-class`)');

plugin.apply(mockCompiler);

expect(registeredFn).not.toBe(undefined);

expect(() => registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.browser.js' })).toThrow('`create-react-class` is restricted from being used');

expect(fs.readFileSync).toHaveBeenCalledTimes(1);

expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});

it('should call validateAppConfig with the file content if it containts `.appConfig`', () => {
const plugin = new RestrictRuntimeSymbols();

let registeredFn;
const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn((_, fn) => {
registeredFn = fn;
}),
},
},
};

fs.readFileSync.mockImplementationOnce(() => 'Module.appConfig = `someConfig`;');

plugin.apply(mockCompiler);

expect(registeredFn).not.toBe(undefined);

registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.browser.js' });

expect(validateAppConfig).toHaveBeenCalledTimes(1);
expect(validateAppConfig).toHaveBeenNthCalledWith(1, 'Module.appConfig = `someConfig`;');

expect(fs.readFileSync).toHaveBeenCalledTimes(1);

expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});

it('should thrown an error if validateAppConfig returns messages', () => {
const plugin = new RestrictRuntimeSymbols();

let registeredFn;
const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn((_, fn) => {
registeredFn = fn;
}),
},
},
};

validateAppConfig.mockImplementationOnce(() => ['Error Message Mock']);
fs.readFileSync.mockImplementationOnce(() => 'Module.appConfig = `someConfig`;');

plugin.apply(mockCompiler);

expect(registeredFn).not.toBe(undefined);

expect(() => registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.browser.js' })).toThrow('appConfig validation failed with the following messages: [ Error Message Mock ]');

expect(validateAppConfig).toHaveBeenCalledTimes(1);
expect(validateAppConfig).toHaveBeenNthCalledWith(1, 'Module.appConfig = `someConfig`;');

expect(fs.readFileSync).toHaveBeenCalledTimes(1);

expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});

it('should do nothing for other bundles', () => {
const plugin = new RestrictRuntimeSymbols();

let registeredFn;
const mockCompiler = {
hooks: {
assetEmitted: {
tap: jest.fn((_, fn) => {
registeredFn = fn;
}),
},
},
};

validateAppConfig.mockImplementationOnce(() => ['Error Message Mock']);
fs.readFileSync.mockImplementationOnce(() => 'Module.appConfig = `create-react-class`;');

plugin.apply(mockCompiler);

expect(registeredFn).not.toBe(undefined);

registeredFn('fileNameMock', { targetPath: 'target/Path/Mock.other.js' });

expect(validateAppConfig).toHaveBeenCalledTimes(0);
expect(fs.readFileSync).toHaveBeenCalledTimes(0);

expect(mockCompiler.hooks.assetEmitted.tap.mock.calls[0][0]).toBe('RestrictRuntimeSymbols');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

jest.mock('../../utils/validateNodeEnv');

jest.mock('@americanexpress/one-app-dev-bundler', () => {});

describe('webpack/one-amex.base', () => {
let nodeEnv;

Expand Down Expand Up @@ -79,15 +81,15 @@ describe('webpack/one-amex.base', () => {
expect.assertions(2);
process.env.NODE_ENV = 'development';
const webpackConfig = (await import('../../webpack/webpack.common.js')).default;
expect(webpackConfig.plugins).toHaveLength(1);
expect(webpackConfig.plugins).toHaveLength(2);
expect(webpackConfig.plugins).toMatchSnapshot();
});

it('should add loader options plugin in production', async () => {
expect.assertions(2);
process.env.NODE_ENV = 'production';
const webpackConfig = (await import('../../webpack/webpack.common.js')).default;
expect(webpackConfig.plugins).toHaveLength(2);
expect(webpackConfig.plugins).toHaveLength(3);
expect(webpackConfig.plugins).toMatchSnapshot();
});
});
4 changes: 2 additions & 2 deletions packages/one-app-bundler/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@americanexpress/one-app-bundler",
"version": "7.0.1",
"version": "7.0.2",
"description": "A command line interface(CLI) tool for bundling One App and its modules.",
"main": "index.js",
"module": "true",
Expand Down Expand Up @@ -40,7 +40,7 @@
],
"license": "Apache-2.0",
"dependencies": {
"@americanexpress/one-app-dev-bundler": "^1.7.1",
"@americanexpress/one-app-dev-bundler": "^1.7.2",
"@americanexpress/one-app-locale-bundler": "^6.6.0",
"@babel/core": "^7.22.20",
"ajv": "^8.12.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import fs from 'node:fs';
import {
validateAppConfig,
} from '@americanexpress/one-app-dev-bundler';

class RestrictRuntimeSymbols {
// eslint-disable-next-line class-methods-use-this -- no need for this
apply(compiler) {
compiler.hooks.assetEmitted.tap('RestrictRuntimeSymbols', (file, { targetPath }) => {
if (targetPath.endsWith('.node.js')) {
const initialContent = fs.readFileSync(targetPath, 'utf8');
if (initialContent.match(/create-react-class/)) {
throw new Error('`create-react-class` is restricted from being used');
}
} else if (targetPath.endsWith('rowser.js')) { // catch browser and legacyBrowser
const initialContent = fs.readFileSync(targetPath, 'utf8');

if (initialContent.match(/create-react-class/)) {
throw new Error('`create-react-class` is restricted from being used');
}

if (initialContent.match(/.appConfig/)) {
const messages = [];
validateAppConfig(initialContent).forEach((message) => messages.push(message));
if (messages.length > 0) {
throw new Error(`appConfig validation failed with the following messages: [ ${messages.join('/n,')} ]`);
}
}
}
});
}
}

export default RestrictRuntimeSymbols;
2 changes: 2 additions & 0 deletions packages/one-app-bundler/webpack/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import webpack from 'webpack';
import TerserPlugin from 'terser-webpack-plugin';
import validateNodeEnvironment from '../utils/validateNodeEnv.js';
import RestrictRuntimeSymbols from './plugins/restrict-runtime-symbols.js';

validateNodeEnvironment();

Expand All @@ -31,6 +32,7 @@ const productionPlugins = [
];

const plugins = [
new RestrictRuntimeSymbols(),
new webpack.EnvironmentPlugin([
'NODE_ENV',
]),
Expand Down
11 changes: 11 additions & 0 deletions packages/one-app-dev-bundler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## [1.7.2](https://github.com/americanexpress/one-app-cli/compare/@americanexpress/[email protected]...@americanexpress/[email protected]) (2024-03-20)


### Bug Fixes

* **appConfig:** restore check to app config ([08f62d2](https://github.com/americanexpress/one-app-cli/commit/08f62d2e8c2eadb4a9751ffd7ac5c51553972e8e))





## [1.7.1](https://github.com/americanexpress/one-app-cli/compare/@americanexpress/[email protected]...@americanexpress/[email protected]) (2024-03-12)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ const isNodeForExternals = (node, ancestors) => {
return isProvidingExternals(assignmentNode);
};

const validateAppConfig = (moduleString) => {
export const validateAppConfig = (moduleString) => {
const messages = [];
const ast = acorn.parse(moduleString, { ecmaVersion: 'latest' });

Expand Down
2 changes: 2 additions & 0 deletions packages/one-app-dev-bundler/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ export { bundleExternalFallbacks } from './utils/bundle-external-fallbacks.js';

export const devBuildModule = _devBuildModule;

export { validateAppConfig } from './esbuild/plugins/restrict-runtime-symbols.js';

export default _devBuildModule;
Loading

0 comments on commit 61edf75

Please sign in to comment.