From d0ce7f1f89e770afda63a54d0992b0e33e1ae427 Mon Sep 17 00:00:00 2001
From: Tom Pereira
Date: Tue, 24 Dec 2024 17:31:32 +0000
Subject: [PATCH 01/44] change initial commit message in changelogs (#3)
---
docs/CHANGELOG.md | 2 +-
packages/features/docs/CHANGELOG.md | 2 +-
packages/react-pointcuts/docs/CHANGELOG.md | 2 +-
packages/ssr/docs/CHANGELOG.md | 2 +-
packages/webpack/docs/CHANGELOG.md | 3 +--
5 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index fe59d05..6f9d606 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -233,4 +233,4 @@ This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
### Added
-- Initial version, copying code from PLP.
+- Initial commit.
diff --git a/packages/features/docs/CHANGELOG.md b/packages/features/docs/CHANGELOG.md
index be37a9f..abc3dd8 100644
--- a/packages/features/docs/CHANGELOG.md
+++ b/packages/features/docs/CHANGELOG.md
@@ -93,4 +93,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Initial version, copying code from PLP
+- Initial commit.
diff --git a/packages/react-pointcuts/docs/CHANGELOG.md b/packages/react-pointcuts/docs/CHANGELOG.md
index 10c985a..932854d 100644
--- a/packages/react-pointcuts/docs/CHANGELOG.md
+++ b/packages/react-pointcuts/docs/CHANGELOG.md
@@ -103,4 +103,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Initial version, copying code from PLP
+- Initial commit.
diff --git a/packages/ssr/docs/CHANGELOG.md b/packages/ssr/docs/CHANGELOG.md
index f7b0824..75ca4ea 100644
--- a/packages/ssr/docs/CHANGELOG.md
+++ b/packages/ssr/docs/CHANGELOG.md
@@ -83,4 +83,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Initial version, copying code from PLP
+- Initial commit.
diff --git a/packages/webpack/docs/CHANGELOG.md b/packages/webpack/docs/CHANGELOG.md
index ae2c30c..5102394 100644
--- a/packages/webpack/docs/CHANGELOG.md
+++ b/packages/webpack/docs/CHANGELOG.md
@@ -103,5 +103,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Initial version, copying code from PLP
-- Added unit tests around the plugin itself, not originally developed in PLP
+- Initial commit
From 27e436a05e74b57ec5de78cb88fe09594c55c70e Mon Sep 17 00:00:00 2001
From: Tom Pereira <10725179+TomStrepsil@users.noreply.github.com>
Date: Thu, 30 Jan 2025 15:30:26 +0000
Subject: [PATCH 02/44] [#18] Fix JSDoc module names (#19)
* rename to proper module namespace
* update docs links
* update versions
* web toggle point in readme title
* fixup changelog from revised 0.x range
* 2.0.0 -> 0.5.0 in oss version scheme
* fix broken link syntax in CHANGELOG
* consistent quoting
* more version history issues
* fixup module name in jsdoc
* add web
remove sdkInstanceProvider
* remove SDKInstanceProvider
* fixup jsdoc dedupe
* tweak
* clarity re: ssr package
* casing etc
---
docs/CHANGELOG.md | 17 +++++++++-----
docs/README.md | 2 +-
docs/dedupeExternalJsdocPlugin.js | 10 ++++-----
package-lock.json | 12 +++++-----
package.json | 2 +-
packages/features/docs/CHANGELOG.md | 10 +++++++--
packages/features/docs/README.md | 2 +-
packages/features/package.json | 2 +-
packages/features/src/global.js | 14 ++++++------
packages/features/src/global/store.js | 10 ++++-----
.../features/src/nodeRequestScoped/store.js | 10 ++++-----
packages/features/src/reactContext/store.js | 10 ++++-----
.../src/ssrBackedReactContext/store.js | 12 +++++-----
packages/react-pointcuts/docs/CHANGELOG.md | 8 ++++++-
packages/react-pointcuts/docs/README.md | 2 +-
packages/react-pointcuts/package.json | 2 +-
packages/react-pointcuts/src/external.js | 11 ----------
.../src/getCodeSelectionPlugins.js | 2 +-
packages/react-pointcuts/src/index.js | 2 +-
.../src/withTogglePointFactory/index.js | 8 +++----
.../src/withToggledHookFactory/index.js | 8 +++----
packages/ssr/docs/CHANGELOG.md | 8 ++++++-
packages/ssr/docs/README.md | 2 +-
packages/ssr/package.json | 2 +-
packages/ssr/src/external.js | 11 ----------
packages/ssr/src/index.js | 4 ++--
.../ssr/src/serializationFactory/index.js | 22 +++++++++----------
packages/ssr/src/withJsonIsomorphism/index.js | 2 +-
packages/webpack/docs/CHANGELOG.md | 6 +++++
packages/webpack/docs/README.md | 2 +-
packages/webpack/package.json | 2 +-
packages/webpack/src/index.js | 2 +-
.../src/plugins/togglePointInjection/index.js | 2 +-
33 files changed, 115 insertions(+), 106 deletions(-)
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 6f9d606..532c7d8 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -14,6 +14,13 @@ N.B. See changelogs for individual packages, where most change will occur:
This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
+## [0.10.2] - 2024-12-26
+
+### Fixed
+
+- "Toggle Point" to "Web Toggle Point" in title of `README.md`
+- fixed the dedupe external JSDoc plugin, after move to type imports
+
## [0.10.1] - 2024-12-24
### Fixed
@@ -73,7 +80,7 @@ This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
### Fixed
-- Removed old `yarn.lock` left over from 1.0.3 update.
+- Removed old `yarn.lock` left over from 0.4.3 update.
## Added
@@ -85,7 +92,7 @@ This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
- Moved to v4 of [`upload-artifact`](https://github.com/actions/upload-artifact) and [`download-artifact`](https://github.com/actions/download-artifact) actions
- Changed nature of pre-release packages to `beta` from `alpha` (better matching the reality of how these pre-releases are used)
-- Fixed up contribution guide since version 2.0.0 added the proposed update checks
+- Fixed up contribution guide since version 0.5.0 added the proposed update checks
- Updated to JSDoc 4, issue with factories resolved
### Changed
@@ -127,7 +134,7 @@ This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
### Fixed
-- Fixup documentation left fallow from package split (2.0.0)
+- Fixup documentation left fallow from package split (0.5.0)
- Upgrade serialize-javascript to 6.0.2 to avoid [`SNYK-JS-SERIALIZEJAVASCRIPT-614760`](https://security.snyk.io/vuln/SNYK-JS-SERIALIZEJAVASCRIPT-6147607)
- snyk ignore [`SNYK-JS-INFLIGHT-6095116`](https://security.snyk.io/vuln/SNYK-JS-INFLIGHT-6095116)
- move to use asos runner groups
@@ -157,7 +164,7 @@ This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
### Changed
- Split the "app" package into separate "ssr", "features" and "react-pointcuts" packages.
-- Move to explicit rather than wildcard workspaces, to enable reification of the repo when publishing (waiting on [https://github.com/Roaders/workspace-version/issues/3](an issue to resolve))
+- Move to explicit rather than wildcard workspaces, to enable reification of the repo when publishing (waiting on [an issue to resolve](https://github.com/Roaders/workspace-version/issues/3))
- Updated the `dedupeExternalJsdocPlugin` to de-duplicate members of external namespaces, rather than just the namespaces themselves (to ensure we don't duplicate React, HostApplication etc. in the html documentation)
- Updated packages for snyk vulnerabilities, populated policy file
- Removed redundant export fields from workspace `package.json`
@@ -175,7 +182,7 @@ This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
### Added
-- Danger support, with checks for CHANGELOG.md updates and package-lock.json updates
+- Danger support, with checks for `CHANGELOG.md` updates and `package-lock.json` updates
### Fixed
diff --git a/docs/README.md b/docs/README.md
index 116c4fd..e6e59fa 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,5 +1,5 @@
-
Toggle Point
+ Web Toggle Point
A library providing a means to toggle or branch web application code.
diff --git a/docs/dedupeExternalJsdocPlugin.js b/docs/dedupeExternalJsdocPlugin.js
index e339a52..56ee304 100644
--- a/docs/dedupeExternalJsdocPlugin.js
+++ b/docs/dedupeExternalJsdocPlugin.js
@@ -18,15 +18,15 @@ exports.defineTags = function (dictionary) {
.synonym("external");
};
-const seenExternals = new Map();
+const seen = new Map();
exports.handlers = {
jsdocCommentFound: function (e) {
if (e.filename.endsWith("external.js")) {
- const match = e.comment.match(/external:(\S+)/);
+ const match = e.comment.match(/(?:[\s\S]*@typedef \{.+\} (?.+))?[\s\S]+external:(?\S+)/);
if (match) {
- const [external] = match;
- if (!seenExternals.has(external)) {
- seenExternals.set(external, true);
+ const symbol = match.groups.typedef || match.groups.external;
+ if (!seen.has(symbol)) {
+ seen.set(symbol, true);
} else {
e.comment = "/**/";
}
diff --git a/package-lock.json b/package-lock.json
index e3b0abd..71ede54 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@asos/web-toggle-point",
- "version": "0.10.1",
+ "version": "0.10.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@asos/web-toggle-point",
- "version": "0.10.1",
+ "version": "0.10.2",
"license": "MIT",
"workspaces": [
"packages/features",
@@ -20346,7 +20346,7 @@
},
"packages/features": {
"name": "@asos/web-toggle-point-features",
- "version": "0.3.0",
+ "version": "0.3.1",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0"
@@ -20403,7 +20403,7 @@
},
"packages/react-pointcuts": {
"name": "@asos/web-toggle-point-react-pointcuts",
- "version": "0.4.0",
+ "version": "0.4.2",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0"
@@ -20441,7 +20441,7 @@
},
"packages/ssr": {
"name": "@asos/web-toggle-point-ssr",
- "version": "0.2.0",
+ "version": "0.2.1",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
@@ -20477,7 +20477,7 @@
},
"packages/webpack": {
"name": "@asos/web-toggle-point-webpack",
- "version": "0.7.2",
+ "version": "0.7.3",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
diff --git a/package.json b/package.json
index 5c5e40e..d72f35a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@asos/web-toggle-point",
- "version": "0.10.1",
+ "version": "0.10.2",
"repository": "git@github.com:asos/web-toggle-point.git",
"homepage": "https://asos.github.io/web-toggle-point/",
"license": "MIT",
diff --git a/packages/features/docs/CHANGELOG.md b/packages/features/docs/CHANGELOG.md
index abc3dd8..fa7b6a2 100644
--- a/packages/features/docs/CHANGELOG.md
+++ b/packages/features/docs/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.3.1] - 2024-12-26
+
+### Fixed
+
+- updated some errant JSDoc namespaces
+
## [0.3.0] - 2024-11-28
### Changed
@@ -32,7 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- updated to latest `@testing-library/react` to remove errant warning about import of `act`
- updated to `react@18.3.1`, set minimum required react to `17`
- - technically a breaking change, but `jsx-runtime` already introduced in [version 1.0.0](#100---2023-09-12)... so was already broken, oops.
+ - technically a breaking change, but `jsx-runtime` already introduced in [version 0.1.0](#010---2023-09-12)... so was already broken, oops.
- renamed commonJs exports to have `.cjs` extension to prevent `[ERR_REQUIRE_ESM]` errors in consumers that aren't `"type": "module"`
## [0.2.2] - 2024-12-26
@@ -61,7 +67,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
-- Fixup documentation left fallow from package split (0.1.0)
+- Fixup documentation left fallow from package split ([version 0.1.0](#010---2023-09-12))
## [0.1.1] - 2023-11-16
diff --git a/packages/features/docs/README.md b/packages/features/docs/README.md
index 0353466..fd7cdef 100644
--- a/packages/features/docs/README.md
+++ b/packages/features/docs/README.md
@@ -8,7 +8,7 @@ A store should be chosen based on the requirement for global or partitioned stat
## Usage
-See: [JSDoc output](https://asos.github.io/web-toggle-point/module-asos-web-toggle-point-features.html)
+See: [JSDoc output](https://asos.github.io/web-toggle-point/module-web-toggle-point-features.html)
> [!WARNING]
> ### Use with React 17
diff --git a/packages/features/package.json b/packages/features/package.json
index 36abbcf..e38f533 100644
--- a/packages/features/package.json
+++ b/packages/features/package.json
@@ -1,7 +1,7 @@
{
"name": "@asos/web-toggle-point-features",
"description": "toggle point features code",
- "version": "0.3.0",
+ "version": "0.3.1",
"license": "MIT",
"type": "module",
"main": "./lib/main.es5.cjs",
diff --git a/packages/features/src/global.js b/packages/features/src/global.js
index abf4590..bd618e8 100644
--- a/packages/features/src/global.js
+++ b/packages/features/src/global.js
@@ -2,21 +2,21 @@ import "./external";
/**
* Application code for holding feature toggle state
- * @module toggle-point-features
+ * @module web-toggle-point-features
*/
/**
* Interface for feature toggle stores
*
* @interface FeaturesStore
- * @memberof module:toggle-point-features
+ * @memberof module:web-toggle-point-features
*/
/**
* Method to return the value of the feature toggle store.
* For {@link https://reactjs.org/docs/context.html|React context}-backed feature stores, this should be called following {@link https://react.dev/warnings/invalid-hook-call-warning|the rules of hooks}
*
* @function
- * @memberof module:toggle-point-features
+ * @memberof module:web-toggle-point-features
* @name FeaturesStore#getFeatures
*/
@@ -24,13 +24,13 @@ import "./external";
* Interface for singleton value-based feature toggle stores
*
* @interface SingletonFeaturesStore
- * @memberof module:toggle-point-features
+ * @memberof module:web-toggle-point-features
*/
/**
* Method to set a value to the feature toggle store.
*
* @function
- * @memberof module:toggle-point-features
+ * @memberof module:web-toggle-point-features
* @name SingletonFeaturesStore#useValue
* @param {object} params parameters
* @param {object} params.value A value to store, used to drive feature toggles.
@@ -40,13 +40,13 @@ import "./external";
* Interface for {@link https://reactjs.org/docs/context.html|React context}-based feature toggle stores
*
* @interface ContextFeaturesStore
- * @memberof module:toggle-point-features
+ * @memberof module:web-toggle-point-features
*/
/**
* Method to create a React context provider, linked to the features store.
*
* @function
- * @memberof module:toggle-point-features
+ * @memberof module:web-toggle-point-features
* @name ContextFeaturesStore#providerFactory
* @returns {external:React.Component} A react context provider that accepts a `value` prop, representing the feature toggle state.
*/
diff --git a/packages/features/src/global/store.js b/packages/features/src/global/store.js
index 7722bd3..2a0c8da 100644
--- a/packages/features/src/global/store.js
+++ b/packages/features/src/global/store.js
@@ -8,16 +8,16 @@ const storeMap = new WeakMap();
* A thin wrapper around a singleton, used as an extension point for future plugins.
* Consider {@link https://github.com/christophehurpeau/deep-freeze-es6|deep freezing} the value to prevent accidental mutation, if this is intended to be static.
* For reactive decisions, consider implementing something that allows for reactivity e.g. a {@link https://github.com/pmndrs/valtio|valtio/vanilla} proxy, and subscribe appropriately in a toggle point.
- * @memberof module:toggle-point-features
- * @returns {module:toggle-point-features.globalFeaturesStore} A store for features, held globally in the application.
+ * @memberof module:web-toggle-point-features
+ * @returns {module:web-toggle-point-features.globalFeaturesStore} A store for features, held globally in the application.
*/
const globalFeaturesStoreFactory = () => {
const identifier = Symbol();
/**
* @name globalFeaturesStore
- * @memberof module:toggle-point-features
- * @implements module:toggle-point-features.FeaturesStore
- * @implements module:toggle-point-features.SingletonFeaturesStore
+ * @memberof module:web-toggle-point-features
+ * @implements module:web-toggle-point-features.FeaturesStore
+ * @implements module:web-toggle-point-features.SingletonFeaturesStore
*/
return {
useValue: ({ value }) => {
diff --git a/packages/features/src/nodeRequestScoped/store.js b/packages/features/src/nodeRequestScoped/store.js
index 0092fb4..c2232df 100644
--- a/packages/features/src/nodeRequestScoped/store.js
+++ b/packages/features/src/nodeRequestScoped/store.js
@@ -4,17 +4,17 @@ import { AsyncLocalStorage } from "async_hooks";
* A factory function used to create a store for features, held in request-scoped global value.
* Should only be used server-side, for anything user or request specific.
* A thin wrapper around node {@link https://nodejs.org/api/async_context.html#class-asynclocalstorage|AsyncLocalStorage}, used as an extension point for future plugins.
- * @memberof module:toggle-point-features
- * @returns {module:toggle-point-features.requestScopedFeaturesStore} A store for features, scoped for the current request.
+ * @memberof module:web-toggle-point-features
+ * @returns {module:web-toggle-point-features.requestScopedFeaturesStore} A store for features, scoped for the current request.
*/
const requestScopedFeaturesStoreFactory = () => {
const store = new AsyncLocalStorage();
/**
* @name requestScopedFeaturesStore
- * @memberof module:toggle-point-features
- * @implements module:toggle-point-features.FeaturesStore
- * @implements module:toggle-point-features.SingletonFeaturesStore
+ * @memberof module:web-toggle-point-features
+ * @implements module:web-toggle-point-features.FeaturesStore
+ * @implements module:web-toggle-point-features.SingletonFeaturesStore
*/
return {
useValue: ({ value, scopeCallBack }) => {
diff --git a/packages/features/src/reactContext/store.js b/packages/features/src/reactContext/store.js
index db64c55..6ef45cb 100644
--- a/packages/features/src/reactContext/store.js
+++ b/packages/features/src/reactContext/store.js
@@ -4,17 +4,17 @@ import PropTypes from "prop-types";
/**
* A factory function used to create a store for features, held in a {@link https://reactjs.org/docs/context.html|React context}.
* A thin wrapper around a context, used as an extension point for future plugins.
- * @memberof module:toggle-point-features
- * @returns {module:toggle-point-features.reactContextFeaturesStore} A store for features, held within a {@link https://reactjs.org/docs/context.html|React context}.
+ * @memberof module:web-toggle-point-features
+ * @returns {module:web-toggle-point-features.reactContextFeaturesStore} A store for features, held within a {@link https://reactjs.org/docs/context.html|React context}.
*/
const reactContextFeaturesStoreFactory = ({ name }) => {
const context = createContext();
/**
* @name reactContextFeaturesStore
- * @memberof module:toggle-point-features
- * @implements module:toggle-point-features.FeaturesStore
- * @implements module:toggle-point-features.ContextFeaturesStore
+ * @memberof module:web-toggle-point-features
+ * @implements module:web-toggle-point-features.FeaturesStore
+ * @implements module:web-toggle-point-features.ContextFeaturesStore
*/
return {
providerFactory: () => {
diff --git a/packages/features/src/ssrBackedReactContext/store.js b/packages/features/src/ssrBackedReactContext/store.js
index ea91d06..44b624f 100644
--- a/packages/features/src/ssrBackedReactContext/store.js
+++ b/packages/features/src/ssrBackedReactContext/store.js
@@ -3,9 +3,9 @@ import reactContextFeaturesStoreFactory from "../reactContext/store";
/**
* A factory function used to create a store for features, held in a {@link https://reactjs.org/docs/context.html|React context}, backed by server-side rendering.
- * A wrapper around a {@link module:toggle-point-features.reactContextFeaturesStore|reactContextFeaturesStore}, with server-side rendering supplied by the {@link module:toggle-point-ssr|toggle-point-ssr} package.
- * @memberof module:toggle-point-features
- * @returns {module:toggle-point-features.ssrBackedReactContextFeaturesStore} A store for features, held within a {@link https://reactjs.org/docs/context.html|React context}.
+ * A wrapper around a {@link module:web-toggle-point-features.reactContextFeaturesStore|reactContextFeaturesStore}, with server-side rendering supplied by the {@link module:web-toggle-point-ssr|toggle-point-ssr} package.
+ * @memberof module:web-toggle-point-features
+ * @returns {module:web-toggle-point-features.ssrBackedReactContextFeaturesStore} A store for features, held within a {@link https://reactjs.org/docs/context.html|React context}.
*/
const ssrBackedReactContextFeaturesStoreFactory = ({
namespace = "toggles",
@@ -18,9 +18,9 @@ const ssrBackedReactContextFeaturesStoreFactory = ({
/**
* @name ssrBackedReactContextFeaturesStore
- * @memberof module:toggle-point-features
- * @implements module:toggle-point-features.FeaturesStore
- * @implements module:toggle-point-features.ContextFeaturesStore
+ * @memberof module:web-toggle-point-features
+ * @implements module:web-toggle-point-features.FeaturesStore
+ * @implements module:web-toggle-point-features.ContextFeaturesStore
*/
return {
providerFactory: () => {
diff --git a/packages/react-pointcuts/docs/CHANGELOG.md b/packages/react-pointcuts/docs/CHANGELOG.md
index 932854d..cd6be4f 100644
--- a/packages/react-pointcuts/docs/CHANGELOG.md
+++ b/packages/react-pointcuts/docs/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.4.2] - 2024-12-26
+
+### Fixed
+
+- updated some errant JSDoc namespaces
+
## [0.4.1] - 2024-12-17
### Removed
@@ -33,7 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- a `Map` of features (de-coupling from a webpack-specific data structure)
- a [javascript module](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), rather than its `default` export (preparing for support of named exports)
- updated to `react@18.3.1`, set minimum required react to `17`
- - technically a breaking change, but `jsx-runtime` already introduced in [version 1.0.0](#100---2023-09-05)... so was already broken, oops.
+ - technically a breaking change, but `jsx-runtime` already introduced in [version 0.1.0](#010---2023-09-05)... so was already broken, oops.
- moved package to `"type": "module"` and renamed commonJs exports to have `.cjs` extension to prevent `[ERR_REQUIRE_ESM]` errors in consumers that aren't `"type": "module"`
### Fixed
diff --git a/packages/react-pointcuts/docs/README.md b/packages/react-pointcuts/docs/README.md
index 8fb4694..92347dc 100644
--- a/packages/react-pointcuts/docs/README.md
+++ b/packages/react-pointcuts/docs/README.md
@@ -18,7 +18,7 @@ Both accept plugins, currently supporting a hook called during code activation (
## Usage
-See: [JSDoc output](https://asos.github.io/web-toggle-point/module-asos-web-toggle-point-react-pointcuts.html)
+See: [JSDoc output](https://asos.github.io/web-toggle-point/module-web-toggle-point-react-pointcuts.html)
> [!WARNING]
> ### Use with React 17
diff --git a/packages/react-pointcuts/package.json b/packages/react-pointcuts/package.json
index 62282e7..7ade338 100644
--- a/packages/react-pointcuts/package.json
+++ b/packages/react-pointcuts/package.json
@@ -1,7 +1,7 @@
{
"name": "@asos/web-toggle-point-react-pointcuts",
"description": "react pointcut code",
- "version": "0.4.0",
+ "version": "0.4.2",
"license": "MIT",
"type": "module",
"main": "./lib/main.es5.cjs",
diff --git a/packages/react-pointcuts/src/external.js b/packages/react-pointcuts/src/external.js
index ef62d00..d3834a4 100644
--- a/packages/react-pointcuts/src/external.js
+++ b/packages/react-pointcuts/src/external.js
@@ -2,17 +2,6 @@
* Code expected in the host application
* @external HostApplication
*/
-/**
- * A factory for SDKs; should return an instance of asos-web-features when called with "features"
- * @callback external:HostApplication.sdkInstanceProvider
- * @async
- * @type {Function}
- * @param {string} sdkName Name of the SDK to access; will be passed "features"
- * @returns {external:asos-web-features}
- * @see SiteChrome SDK interface {@link https://asoscom.atlassian.net/wiki/spaces/WEB/pages/593592455/SCP+-+Interface+Definition#SDK-Instances|SDK Instances}
- * @example
- * const sdkInstance = await sdkInstanceProvider("features");
- */
/**
* A delegate passed to log an error
* @callback external:HostApplication.logError
diff --git a/packages/react-pointcuts/src/getCodeSelectionPlugins.js b/packages/react-pointcuts/src/getCodeSelectionPlugins.js
index 7dde7b2..4aa9b83 100644
--- a/packages/react-pointcuts/src/getCodeSelectionPlugins.js
+++ b/packages/react-pointcuts/src/getCodeSelectionPlugins.js
@@ -1,6 +1,6 @@
/**
* A plugin for the point cuts package
- * @typedef {object} module:toggle-point-react-pointcuts~plugin
+ * @typedef {object} module:web-toggle-point-react-pointcuts~plugin
* @property {string} name plugin name, used as a prefix when creating {@link https://legacy.reactjs.org/docs/higher-order-components.html|React Higher-Order-Components} when toggling
* @property {Function} onCodeSelected hook to be called when a code selection is made
*/
diff --git a/packages/react-pointcuts/src/index.js b/packages/react-pointcuts/src/index.js
index fc91576..b31c5df 100644
--- a/packages/react-pointcuts/src/index.js
+++ b/packages/react-pointcuts/src/index.js
@@ -4,6 +4,6 @@ import "./external";
/**
* Application code for creating a React {@link https://en.wikipedia.org/wiki/Pointcut|pointcut}.
- * @module toggle-point-react-pointcuts
+ * @module web-toggle-point-react-pointcuts
*/
export { withTogglePointFactory, withToggledHookFactory };
diff --git a/packages/react-pointcuts/src/withTogglePointFactory/index.js b/packages/react-pointcuts/src/withTogglePointFactory/index.js
index cd8e6f0..ecd92a2 100644
--- a/packages/react-pointcuts/src/withTogglePointFactory/index.js
+++ b/packages/react-pointcuts/src/withTogglePointFactory/index.js
@@ -7,17 +7,17 @@ import getCodeSelectionPlugins from "../getCodeSelectionPlugins";
{}
/**
* A factory function used to create a withTogglePoint React Higher-Order-Component.
- * @memberof module:toggle-point-react-pointcuts
+ * @memberof module:web-toggle-point-react-pointcuts
* @inner
* @function
* @param {object} params parameters
* @param {function} params.getActiveFeatures a method to get active features. Called honouring the rules of hooks.
* @param {external:HostApplication.logError} params.logError a method that logs errors
* @param {string} [params.variantKey=bucket] A key use to identify a variant from the features data structure. Remaining members of the feature will be passed to the variant as props.
- * @param {Array} [params.plugins] plugins to be used when toggling
+ * @param {Array} [params.plugins] plugins to be used when toggling
* Will be used when a toggled component throws an error that can be caught by an {@link https://reactjs.org/docs/error-boundaries.html|ErrorBoundary}.
* When errors are caught, the control/base code will be used as the fallback component.
- * @returns {module:toggle-point-react-pointcuts.withTogglePoint} withTogglePoint React Higher-Order-Component.
+ * @returns {module:web-toggle-point-react-pointcuts.withTogglePoint} withTogglePoint React Higher-Order-Component.
* @example
* const withTogglePoint = withTogglePointFactory({
* getActiveFeatures,
@@ -37,7 +37,7 @@ const withTogglePointFactory = ({
/**
* A React Higher-Order-Component that wraps a base / control component and swaps in a variant when deemed appropriate by a context
* @function withTogglePoint
- * @memberof module:toggle-point-react-pointcuts
+ * @memberof module:web-toggle-point-react-pointcuts
* @param {ReactComponentModuleNamespaceObject} controlModule The control / base module
* @param {external:React.Component} controlModule.default The control react component
* @param {Map} featuresMap A map of features and their variants, with features as top-level keys and variants as nested keys with modules as the values.
diff --git a/packages/react-pointcuts/src/withToggledHookFactory/index.js b/packages/react-pointcuts/src/withToggledHookFactory/index.js
index 61baeb7..13c7413 100644
--- a/packages/react-pointcuts/src/withToggledHookFactory/index.js
+++ b/packages/react-pointcuts/src/withToggledHookFactory/index.js
@@ -6,13 +6,13 @@ import getCodeSelectionPlugins from "../getCodeSelectionPlugins";
{}
/**
* A factory function used to create a withToggledHook React hook, wrapping an existing hook/function.
- * @memberof module:toggle-point-react-pointcuts
+ * @memberof module:web-toggle-point-react-pointcuts
* @inner
* @function
* @param {object} params parameters
* @param {function} params.getActiveFeatures a method to get active features, which is called honouring the rules of hooks.
- * @param {Array} [params.plugins] plugins to be used when toggling
- * @returns {module:toggle-point-react-pointcuts.withToggledHook} withToggledHook hook function, use to wrap a function (either a hook itself, or a function that must be called wherever a hook can...).
+ * @param {Array} [params.plugins] plugins to be used when toggling
+ * @returns {module:web-toggle-point-react-pointcuts.withToggledHook} withToggledHook hook function, use to wrap a function (either a hook itself, or a function that must be called wherever a hook can...).
* @example
* const getActiveFeatures = () => useContext(myContext);
* const withToggledHook = withToggledHookFactory({
@@ -28,7 +28,7 @@ const withToggledHookFactory = ({ getActiveFeatures, plugins = [] }) => {
/**
* A React hook that wraps a base / control function or hook and swaps in a variant when deemed appropriate by a context
* @function withToggledHook
- * @memberof module:toggle-point-react-pointcuts
+ * @memberof module:web-toggle-point-react-pointcuts
* @param {ReactHookModuleNamespaceObject} controlModule The control / base module
* @param {(external:React.Hook|function)} controlModule.default The control react hook or function.
* @param {Map} featuresMap A map of features and their variants, with features as top-level keys and variants as nested keys with modules as the values.
diff --git a/packages/ssr/docs/CHANGELOG.md b/packages/ssr/docs/CHANGELOG.md
index 75ca4ea..31ed972 100644
--- a/packages/ssr/docs/CHANGELOG.md
+++ b/packages/ssr/docs/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.1] - 2024-12-26
+
+### Fixed
+
+- updated some errant JSDoc namespaces
+
## [0.2.0] - 2024-12-17
### Removed
@@ -50,7 +56,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- updated to latest `@testing-library/react` to remove errant warning about import of `act`
- updated to `react@18.3.1`, set minimum required react to `17`
- - technically a breaking change, but `jsx-runtime` already introduced in [version 1.0.0](#100---2023-09-05)... so was already broken, oops.
+ - technically a breaking change, but `jsx-runtime` already introduced in [version 0.1.0](#010---2023-09-05)... so was already broken, oops.
- renamed commonJs exports to have `.cjs` extension to prevent `[ERR_REQUIRE_ESM]` errors in consumers that aren't `"type": "module"`
## [0.1.2] - 2024-12-06
diff --git a/packages/ssr/docs/README.md b/packages/ssr/docs/README.md
index 78845c2..54873d8 100644
--- a/packages/ssr/docs/README.md
+++ b/packages/ssr/docs/README.md
@@ -28,7 +28,7 @@ For the browser:
## Usage
-See: [JSDoc output](https://asos.github.io/web-toggle-point/module-asos-web-toggle-point-ssr.html)
+See: [JSDoc output](https://asos.github.io/web-toggle-point/module-web-toggle-point-ssr.html)
> [!WARNING]
> ### Use with React 17
diff --git a/packages/ssr/package.json b/packages/ssr/package.json
index 2a6578d..10b2ff7 100644
--- a/packages/ssr/package.json
+++ b/packages/ssr/package.json
@@ -1,7 +1,7 @@
{
"name": "@asos/web-toggle-point-ssr",
"description": "toggle point server side rendering code",
- "version": "0.2.0",
+ "version": "0.2.1",
"license": "MIT",
"type": "module",
"main": "./lib/main.es5.cjs",
diff --git a/packages/ssr/src/external.js b/packages/ssr/src/external.js
index 3603746..68c0153 100644
--- a/packages/ssr/src/external.js
+++ b/packages/ssr/src/external.js
@@ -2,17 +2,6 @@
* Code expected in the host application
* @external HostApplication
*/
-/**
- * A factory for SDKs; should return an instance of asos-web-features when called with "features"
- * @callback external:HostApplication.sdkInstanceProvider
- * @async
- * @type {Function}
- * @param {string} sdkName Name of the SDK to access; will be passed "features"
- * @returns {external:asos-web-features}
- * @see SiteChrome SDK interface {@link https://asoscom.atlassian.net/wiki/spaces/WEB/pages/593592455/SCP+-+Interface+Definition#SDK-Instances|SDK Instances}
- * @example
- * const sdkInstance = await sdkInstanceProvider("features");
- */
/**
* A delegate passed to log a warning
* @callback external:HostApplication.logWarning
diff --git a/packages/ssr/src/index.js b/packages/ssr/src/index.js
index cbba6c8..e4d6750 100644
--- a/packages/ssr/src/index.js
+++ b/packages/ssr/src/index.js
@@ -3,7 +3,7 @@ import withJsonIsomorphism from "./withJsonIsomorphism";
import "./external";
/**
- * Server Side Rendering code for Isomorphic React applications
- * @module asos-web-toggle-point-ssr
+ * Server Side Rendering code for isomorphic / universal applications
+ * @module web-toggle-point-ssr
*/
export { withJsonIsomorphism, serializationFactory };
diff --git a/packages/ssr/src/serializationFactory/index.js b/packages/ssr/src/serializationFactory/index.js
index 53ab300..c3e6794 100644
--- a/packages/ssr/src/serializationFactory/index.js
+++ b/packages/ssr/src/serializationFactory/index.js
@@ -5,16 +5,16 @@ import parse from "html-react-parser";
{}
/**
* A factory for creating a serialization object that has methods for serializing and deserializing JSON data in server-rendered web applications.
- * @memberof module:asos-web-toggle-point-ssr
+ * @memberof module:web-toggle-point-ssr
* @inner
* @function
- * @memberof module:asos-web-toggle-point-ssr
+ * @memberof module:web-toggle-point-ssr
* @inner
* @function
* @param {object} params parameters
* @param {string} params.id The id attribute of the backing application/json script.
* @param {external:HostApplication.logWarning} params.logWarning A method that logs warnings; will be used when malformed JSON is found in the backing store when deserialize on the client, which should only be possible if processed in a system downstream from the origin.
- * @returns {module:asos-web-toggle-point-ssr.serialization} Some serialization / deserialization methods
+ * @returns {module:web-toggle-point-ssr.serialization} Some serialization / deserialization methods
* @example
* const logWarning = (warning) => console.log(warning);
* const id = "app_features";
@@ -23,33 +23,33 @@ import parse from "html-react-parser";
const serializationFactory = ({ id, logWarning }) =>
/**
* @typedef {function} getScriptMarkup
- * @memberof module:asos-web-toggle-point-ssr
+ * @memberof module:web-toggle-point-ssr
* @param {object} params parameters
* @param {object} params.content The JSON content to be serialized.
*/
/**
* @typedef {function} getScriptReactElement
- * @memberof module:asos-web-toggle-point-ssr
+ * @memberof module:web-toggle-point-ssr
* @param {object} params parameters
* @param {object} params.content The JSON content to be serialized.
*/
/**
* @typedef {function} getJSONFromScript
- * @memberof module:asos-web-toggle-point-ssr
+ * @memberof module:web-toggle-point-ssr
* @returns {object} The JSON content of the script element.
*/
/**
* An object containing methods for serializing and deserializing JSON data in server-rendered web applications.
* @typedef {object} serialization
- * @memberof module:asos-web-toggle-point-ssr
- * @property {module:asos-web-toggle-point-ssr.getScriptMarkup} getScriptMarkup Gets a string containing markup for a type="application/json" script element with the specified content.
- * @property {module:asos-web-toggle-point-ssr.getScriptReactElement} getScriptReactElement - Gets a React element for a type="application/json" script element with the specified content.
- * @property {module:asos-web-toggle-point-ssr.getJSONFromScript} getJSONFromScript - Returns the JSON content of the script element.
+ * @memberof module:web-toggle-point-ssr
+ * @property {module:web-toggle-point-ssr.getScriptMarkup} getScriptMarkup Gets a string containing markup for a type="application/json" script element with the specified content.
+ * @property {module:web-toggle-point-ssr.getScriptReactElement} getScriptReactElement - Gets a React element for a type="application/json" script element with the specified content.
+ * @property {module:web-toggle-point-ssr.getJSONFromScript} getJSONFromScript - Returns the JSON content of the script element.
*/
({
/**
- * @memberof module:asos-web-toggle-point-ssr.serialization
+ * @memberof module:web-toggle-point-ssr.serialization
* @param {object} content The JSON content to be serialized.
* @returns {string} A string containing markup for a type="application/json" script element with the specified content.
*/
diff --git a/packages/ssr/src/withJsonIsomorphism/index.js b/packages/ssr/src/withJsonIsomorphism/index.js
index b68c691..8559f37 100644
--- a/packages/ssr/src/withJsonIsomorphism/index.js
+++ b/packages/ssr/src/withJsonIsomorphism/index.js
@@ -8,7 +8,7 @@ import { useState, useEffect } from "react";
* which are then realised into a prop when first hydrating on the client. It will be reactive to subsequent non-`undefined` prop values,
* for that prop.
* The package "browser" export includes the code to read the script, omitted from the "import" / "require" export (server package).
- * @memberof module:asos-web-toggle-point-ssr
+ * @memberof module:web-toggle-point-ssr
* @inner
* @function
* @param {external:React.Component} WrappedComponent The React component that will receive the props.
diff --git a/packages/webpack/docs/CHANGELOG.md b/packages/webpack/docs/CHANGELOG.md
index 5102394..9467746 100644
--- a/packages/webpack/docs/CHANGELOG.md
+++ b/packages/webpack/docs/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.7.3] - 2024-12-26
+
+### Fixed
+
+- updated some errant JSDoc namespaces
+
## [0.7.2] - 2024-12-17
### Removed
diff --git a/packages/webpack/docs/README.md b/packages/webpack/docs/README.md
index 823c534..f4c7b1d 100644
--- a/packages/webpack/docs/README.md
+++ b/packages/webpack/docs/README.md
@@ -20,7 +20,7 @@ The join points are configured using a [glob](https://en.wikipedia.org/wiki/Glob
### Configuration
-See [JSDoc output](https://asos.github.io/web-toggle-point/module-asos-web-toggle-point-webpack.html)
+See [JSDoc output](https://asos.github.io/web-toggle-point/module-web-toggle-point-webpack.html)
Different code paths may have different toggling needs, and may want a toggle point applied in differing ways. Independent point cuts should be configured for each different:
diff --git a/packages/webpack/package.json b/packages/webpack/package.json
index 38fbc45..ec17f81 100644
--- a/packages/webpack/package.json
+++ b/packages/webpack/package.json
@@ -1,7 +1,7 @@
{
"name": "@asos/web-toggle-point-webpack",
"description": "toggle point webpack plugin",
- "version": "0.7.2",
+ "version": "0.7.3",
"license": "MIT",
"type": "module",
"main": "./lib/main.cjs",
diff --git a/packages/webpack/src/index.js b/packages/webpack/src/index.js
index a99fcdc..a11c1e9 100644
--- a/packages/webpack/src/index.js
+++ b/packages/webpack/src/index.js
@@ -2,6 +2,6 @@ import "./external.js";
/**
* Webpack code for injecting toggle points
- * @module toggle-point-webpack
+ * @module web-toggle-point-webpack
*/
export { TogglePointInjection } from "./plugins";
diff --git a/packages/webpack/src/plugins/togglePointInjection/index.js b/packages/webpack/src/plugins/togglePointInjection/index.js
index df98970..0148828 100644
--- a/packages/webpack/src/plugins/togglePointInjection/index.js
+++ b/packages/webpack/src/plugins/togglePointInjection/index.js
@@ -9,7 +9,7 @@ import schema from "./schema.json";
/**
* Toggle Point Injection Plugin
- * @memberof module:toggle-point-webpack
+ * @memberof module:web-toggle-point-webpack
* @inner
*/
class TogglePointInjection {
From 1f0cb29d36b158f19c1301eba2c122c0810c146b Mon Sep 17 00:00:00 2001
From: Tom Pereira <10725179+TomStrepsil@users.noreply.github.com>
Date: Thu, 6 Mar 2025 12:18:52 +0000
Subject: [PATCH 03/44] [26] Fix public/scoped package publishing (#27)
* update workflows
* version
* typo
* update chromium linux snaps
* versions for serve update
* package.json repository field
* update root package.lock
* bugs & directories/doc fields
* fix changelog
---------
Co-authored-by: Tom Pereira
---
.github/actions/publish/publish.sh | 2 +-
.github/workflows/release.yaml | 2 ++
docs/CHANGELOG.md | 6 ++++++
examples/serve/docs/CHANGELOG.md | 7 +++++++
examples/serve/package.json | 2 +-
.../-screenshots-control-chromium-linux.png | Bin 1515 -> 1281 bytes
...enshots-st-patricks-day-chromium-linux.png | Bin 3354 -> 3079 bytes
package-lock.json | 14 +++++++-------
package.json | 2 +-
packages/features/docs/CHANGELOG.md | 6 ++++++
packages/features/package.json | 13 ++++++++++++-
packages/react-pointcuts/docs/CHANGELOG.md | 6 ++++++
packages/react-pointcuts/package.json | 13 ++++++++++++-
packages/ssr/docs/CHANGELOG.md | 6 ++++++
packages/ssr/package.json | 13 ++++++++++++-
packages/webpack/docs/CHANGELOG.md | 6 ++++++
packages/webpack/package.json | 13 ++++++++++++-
17 files changed, 97 insertions(+), 14 deletions(-)
diff --git a/.github/actions/publish/publish.sh b/.github/actions/publish/publish.sh
index cd06cdf..cd8920a 100755
--- a/.github/actions/publish/publish.sh
+++ b/.github/actions/publish/publish.sh
@@ -1,2 +1,2 @@
TAG=$([ "$PRE_RELEASE" == "true" ] && echo "--tag=pre-release ")
-npm publish $TAG--workspace=$WORKSPACE 2> publish_stderr_digest.log
+npm publish --access public $TAG--workspace=$WORKSPACE 2> publish_stderr_digest.log
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index eb97d40..ef7b596 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -219,3 +219,5 @@ jobs:
name: ${{ matrix.package.name }}
version: ${{ steps.newVersion.outputs.version }}
is-pre-release: ${{ env.IS_PRE_RELEASE }}
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 532c7d8..42e9399 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -14,6 +14,12 @@ N.B. See changelogs for individual packages, where most change will occur:
This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
+## [0.10.3] - 2025-02-27
+
+### Fixed
+
+- GHA pipelines for publishing to public/scoped NPM repository
+
## [0.10.2] - 2024-12-26
### Fixed
diff --git a/examples/serve/docs/CHANGELOG.md b/examples/serve/docs/CHANGELOG.md
index 126a3c8..9f2b321 100644
--- a/examples/serve/docs/CHANGELOG.md
+++ b/examples/serve/docs/CHANGELOG.md
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.3] - 2025-02-27
+
+### Changed
+
+- updated some linux playwright snapshots
+ - no code changes, so this must be a change in linux chromium. Assets look identical to eye, so presumably need to relax the fuzziness.
+
## [0.2.2] - 2024-12-17
### Removed
diff --git a/examples/serve/package.json b/examples/serve/package.json
index 945644b..20a3f5d 100644
--- a/examples/serve/package.json
+++ b/examples/serve/package.json
@@ -1,6 +1,6 @@
{
"name": "web-toggle-point-serve-example",
- "version": "0.2.0",
+ "version": "0.2.3",
"type": "module",
"private": true,
"scripts": {
diff --git a/examples/serve/src/fixtures/event/playwright.spec.ts-snapshots/-screenshots-control-chromium-linux.png b/examples/serve/src/fixtures/event/playwright.spec.ts-snapshots/-screenshots-control-chromium-linux.png
index 6615aa1a81dce531b97b8f2d111a015ab6a08e19..f1aa0ebed6c0d579a89a296353976c95a38abd46 100644
GIT binary patch
delta 1249
zcmV<71RneA3xNudFn)my&Yb+>UG`%YU6`?^f*U%c*q61R@!uK()RUrEOE
zp4{I7pq}kA#OdlH001CSx2CS*gd+OMdUO6JcDvo8#RP%DFF
zbljMgS+zGGRDX&b%W_hAuu78Epe%8P0w+~Qo8*RjZM2FWr8wAZIz_%RPfjND3a|Ep
zy8&lqR_!fjjgr6?3Y<`C&i1ESHigqcg~swc>zA#25mHW(O@Xs@$!N|Nog!D6-x6oi
zFeIKWu$*Kx=fTaAuKMzf6d9BRyWMUVj10cOtCh}Vv44q@vywk12G5r|^G%c_AInii
z;-uy>IYwuBwJ{H(D45kGRwxI98%o2Ih&efQQObVUE^7qWsS+H
z&}d??>fmryE^55g`8ujsTlXWRCjF)Yw}dTR4}ZFY{yb)wXMf`jQD5at2ZMSO^
zPnnZHjbqUdfsT(0DK;iS`qZVm4!o(0NgIQ3c+VIEAZqfdP>3L;^y-y39Gh~>0{{Sk
zEq}*r$(P%=BiyeLe_MfnZV4-1y+z%6>sV=NpU!|`4ke}c<)IYmhkEG#{^dEuT7B#Q
z4fn@uA_8zN{rM3-b25j=7YnVs9-GXC4}?$Jm<080k7{7*V$wzcgm;Y{02t;x?sX{u
z07S;VPU+1mKuUzPq~B72+IFh2k6<44<$s|R*_3<(vD+o}>GpgPBE(Qik*uJ#?Vf#Q
z<2&|NRK!Pz+Jh7Yt=%<)J^^ufSw)%+HVJa3u4lX0G|`g*Q(++7yFvK0QLd1NbR#p_G1RU3>dv2NG=FOXT?%bg|^jDJRdhu{3
z003sQxvsA6>VMU%008iKy!Q6?l9G}$XU=4F!Zd#oD2nR!`ttJf-Q8U@hRw~*_V#v>
zNW|fAsNF;K*-2`3Y`gpzG!-o%VZ*OBh4Gj%Xo;)E*2!dcqNr}Z`
zSzTQ<8jUO#%j5B&D7v$=)6~?|)zuY=LK9u2d?0^X84y=@bfuo12?>_@hUU8XFs#p21yNs@#znGCn*=jX4luM=Lxfqy{Y)TvWgyQQV&?%lfthqxKYSCN_mafN;G
z-~nMicDwz;g$o=G2e)AP6YfhwDaaRM#sD91ai!1^=?Wy`8+zi4!LZ3JNS1%f!TlR;x`iAqiPoS$JSh
zPEH0_K{Yn6uyMoZ=H@mwHe&7R?0-uJl*FELrKP3A!^43<06~zKFJDeiPv5w4Ln4t>
zRaITPcFpVcuC1+&jEp>f{J5*DE6LQw#l@E{UD9YYU%!4027|M+vllO3G#CuY`{;DK
zTeof%78VKwf+Q1WoOFur6&ow;z`#Ikcv)H5*|TSBYiqxK`xXj?j7DQoQGZb=6iRbn
zGN2@O$9eVYl}sk%a=BbCx1yrLVzFTMt*xz&jt;R{oSmI5lgU1Q{D@zXKoI=#;|JC@
z8jTed75I=+sl+Z*csQHQmPjP{2hnIqe0)A1004u7g9)9ZCxfDBV`JmPhYtzYw^#@l
z;k_~>QY16DxJI9zHa0fe+S)`S5u42}FE9V}=@X@WA(0{-B^mTT_h_g>
n|6oZ&8T!!BP=-DuSX(O1u+tD@
zm(@Y&RzWYTjGbEFVzVc&FX_s;vjXnY_%H#E5Z-uU{D#rR%+{;Xea-wCU_j%VA`
zwo`Gv%X6t;alM<3=C={vL^@H>)T4UdyYv0CdqO3DL&)EX`nYrFqq&{9MPawq+AY-B
zESuig_dv9#cc5>mI)8rYmc3Um@8$a2apg_sQl??PJAV@Zd~{IY*iPAJ+9U
zu7}85^pU~G-m6aB!}rHHetxlb_L6_8wlF}ph#Nn*`rTMDReWZ&24HaCUbDDIreNNr
zq5tbMuYU(ypWKrW+6noi1m=vV(-R&*5?V2}^5flLLj=l$r{Y~PsKi78yfCcY=3v?(
zs>@EgDeQI%>A3TKj-Laf;UXJ9Ti7Wa*hoIUz9+m`Ti|=5+xj>EUx0l(zEhd|WhBxw
zK!*Bz<4t|}u3Kw-lJ(s(1pp!pXG;5R`GlMn?|+sd&z~+99G8VeR?=F`vptUxN&rel
z+WziLrDQlRs;)CNHiaEzJncYGl}sYOs*OrHUZi&i9Wg-w7^N%y#~debjGIoC5vu4)
zIw^Kk0qqcV8=Q1g*zFWjPb3o77I{PgZ0_xU|AU`=dh1{QyYpA!;z9(tcf+T)fBe%w
z{C~yQYxMwi#Q1xkRQ{u>FCmfKl6(5xEHIYNCmc1Kk!1?dkxYRIQp+&>>0*AoWXIFR
zJ+e1lwi%Iz6p;X-S9VI4$An>B7q2u!zCDr8+otU^5J4G9XB4$bl2@`E(!>+eW7GPZ
z8UU0{<TM5?1xRkg@Cd
z=7g1PI0$h80P|gsh|5c=Neo@&Cv+{lSe&$3Oid~Ri2~e>h2)#Bs`^_@-D?=b)IO0)
z9V?m#%EggZwRDq2b(`(w=%%pS*|mGc{_gQ#K6n4%1_0aoH}^z(rrCTye@|uZSAU@5}Ai?bkBpm?BoKu~~e6uVwC$N$3<_)KXJS
z-DegRnfRsDQQZ;>)vZlN2%~9ahTtLQ#0h)#cL4#tDq;%D;`$E&Jd(
zf~3o=ls|Jii0(M7myIDaapVt2H$VG7Pi2~p6s)-1rkpl3cXwWLGRC>700W=>l#$<`
zlu4_A#V+yVPaDZ%W^|73+9DC(KFP>n%~uZirIF>;>?Ea^kC9#f=_FJFfPWRVBZtQN
zpZHO#n20q?B6Hg(s%en7%=YaO_A0w}i}l5~&W>*S*b<4+NKd`KcqyEHXVzIe!J{MLwFds*U^<^rMHq
zH-*IGwv#UBV&a{ivFw@Gq
za>@JFdq00P;h#FB7IJp$N9zhdtdx53>Cri|@5{FRHLLth=S^j0LE01M40u_Tmy}Tz
z5__M2Ue%cAvZhHSZ4=cZ$oAR(P=&opYv*_;7JIx6eSG8V`QU>G)^FO_H+11QTy$L!
z>G3wK;}_~Rf8i2<>VL%rg!gT~=QFK+va0J;96y#Y^c1S4Wd5;Z=bq6DzLm-ePQj{y
z-
zW}e7eAOOJ0k8YzhWWcgvwUuRDk)wv~xt3RQdCichYc@9~lz#%?wbbs$oF{6-Qf9^x
z1qq?e0K^)L41&;SA)$oQ7^NIo$oxJ#bxtxT{LmM+r~cb}j*HYU1dZ7Q>j`)M-FI7fV}3DJNFJLF5PkGt
z(j@?hB{Irqi^op}?-ufIE>raZh=SZmBO#Omv$L)j0vux@2w9?t5DM^=(rYVYKu}}=
z!^+@Wr>U4LB~%IkZrO2(Aj>z+Ks$;xod0yFa}V1WwAjB2Y}KTX&G=g_*ptDqBM5(<^+wBSvCgA!wP?T
z%$;^1D*zDM`I1qlN#hZfwMZh`B&ua<+GV>Hx-0C}Tf3cGzPOQmqF%29k-^v}AKv!u
zFMZ;>y?@dET77|V8y?;H&oc{)?=4(v7)PT$y?e3qvwR%Oti<
zltbxxE=yFX*r4{aY74C)MJ&NYWF)jCm=!KVC^Uxzh*?(sRkSar56r*swQvNl!H0y|*B;80kU2Ze~
zB?N)%dw>K0%&~p&Lz+rj#^85@pLjwa%$}UFO~=JYX3T1wf?cNxTW7l&2m`KK|fsV7npUE(`nS-?eMNIR4d#9{BRZ+kd|T
zU~ay0YUY*d{Dp0s)FJv%G_p!@dXq-_HKQ~$6)gS04-6=}nm1&L00`aUtI704*{^{P
zDBA99ZjUMe%(u%Gk8zSJu5iHOd6r%AJm!OH`f#^SU>vh-`9ebP?094e%o$JWmgRGz
zB4u;hiYJ@PY@Ui2zB%sEp>$z?LVo~r%6j62&EjeEV7i$s&^>EQSn-te`mTHp9~PKzl_p(KMH`kV;5r4HCK9XfgstT2qn5;ug>KzpA)UD}
zp8u~W4}bB+jq8Peeq#q7*06@V5FHCUn$2cAxZkG!``%}j@4xX4u7{U|-|xV~8rE#=KC!$$(03H$#6xPes0BF2(|00000NkvXXu0mjf
DQGgC^
delta 3339
zcmV+m4fOJd7@8W8Fn-0yzBd+#^j+yT++_0Wet^r2@!&AUxQD1R;ONgw*~_F;Bn59&Zj}_CYeRQ3cNTqk7eVNWCV7)R%N_ybZTr&e=wV`aduvzM`jGs=py96l
zm`-*~YZi@4Q-42e{?l|LBAKYDuBh-uVM$|2i>ie@S<+ZS=!x$7^UuSv;$ssJO$-%;
z-mSa)c0Ium?5Dz?@HCwL9XtJI`rCD;x6#AIHfd|8(J94>DlWqlL#Z}&7pYoAo~P6P
zx}AozO)+(?>e|vXOUV>rQCKW0OC%H7&};x8%p)vkPJfOmM*i8D;5A{^u~|NLJ|i4Q
zylr1#{DARkm(zUv`6dS?zinSE4+|!C*M)So{MT#3?~+jSbz!lM~vdDX~%g{K#09-G;$Y+ezv!W57H
zUikUe&wnQ$pCoj|mgp_R9EO>~v7%bBs4O2lpEvI8Yv5+>1^`nAP3i4{OcBbmMl6`v
zCKXcNV*yT+0bp94@>caeKc|nlbbBUBC{p@Qg6U<2QhUnty_`PtK|c)x44OoUNSi)ZVdY+G}(g
zFRm92qnT)=xS{yudmlX}L1eW7XNm
zYk#yl4Fcd~C@Am(9#J}VH;xPpK
z(C0%2&M@xAjpsKG+&kcE?YcT_b>WM`dTD*QN4Pc3T1}`kOERCld@_E(_z>3+13$Yo
zTTmpZmQ-^Y-06d-FY;f6BCmfT?8pps34h#_zv)`lwGB}l0ASVmRX3mC%$$|!Yw!D7
zvt>{xncX@qA)K}|t|UqXYtA-go2firUAbALkJLKzzv
zgY5=m+kaK3xYn;K8$(dNUN6^(Yg-=cbozp7fmS8tQJJc6Z%GULeXp|k5{_3@eUF$ZJF-d(k%I!qAud)eupmC&V0#iQFF<{7dk#{|w`&^XsH_
zZ8_wsvF498GltBNuYZvXrV94o-5;G1ttQk)e6WZ)@
z`XXRYz`2TZQTwB=&%b`6J|zB(}zsYxSz2$Z*78K0syE8)#m}9FZN#y
z0OJOX%PGrQ61ZeZ;1a_op6vcrw^Rdwhpor=e}0dnID#M;g2j5rDm03Ao)}?jlKRVE!5$zB?x_^a$>*wQbul2
zM>~%OfPZLy^v3*+QT?NKP2L3nYC@e`o;$*EM1R}%ukXg0fi8iWC7HKg+=}y!qheGe
zWHq4%0B@c*9e=fek?$K({iDb=l1*i6by@^LevJ9Cqb#M3rENJFf+@91!_*9uwWZq{
zcev;JWR+%-d_#AEe0L=$*cQRA!Ga>e1JMKWP=BdaF8qCAf7|{k5h+H3NXlZ0P!>@e
zL$JH7=XcZ0e1_Pl<(L~4T
zL9RgzoMFV_p6lal@7pe9Ib}Iy`=QipUhDK9)Q#k-!czWTBkT0khb=Txw34RHAm3b1C
zBw<*>?4h$ASPrlC#|SfqACqz^#ofj|%p=S=naAX1&B`)#_SJ+s#4RMmEkr054tE$%
z#i+Ml+**HSeWkdP!{Bs`tEa7JTYruYbaIXSnfMubRiRasH52(wxeK2c4;<>pk(g01&hKu|H=8qxr+n$1lrJSm=xyGxTBK>P9nc&
zbQZ*J3AH79%iQ5}Ev|MiC3d&}*N(*2KN9>sCXe-+0{}90E~KXpMsi#aRJv28|94>mBh`)t?kv$g4lDRxW7SfTz
zb!tMH7`)kxdr2s?irUs%1VQYX_J(bq0a~3_5Bk?et`EHpp;&mj{C_l`%a7(qBYyk$FIYD25Qpi=qH)Zy(1$*}gD^X>v6Pe)Gsfex
zoF&ReL4Goh(tI4pm|>w0eRv09c4C|PL;?UUp?=a(=*b&F@8o^14}JJM!o0-(AFhOd
V$k~JKp#T5?07*qoL
Date: Thu, 6 Mar 2025 14:23:30 +0000
Subject: [PATCH 04/44] fix registry url etc (#34)
Co-authored-by: Tom Pereira
---
.github/actions/publish/action.yaml | 2 ++
docs/CHANGELOG.md | 6 ++++++
package.json | 2 +-
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/.github/actions/publish/action.yaml b/.github/actions/publish/action.yaml
index bb3659c..2106e92 100644
--- a/.github/actions/publish/action.yaml
+++ b/.github/actions/publish/action.yaml
@@ -21,6 +21,8 @@ runs:
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
+ registry-url: https://registry.npmjs.org/
+ always-auth: true
cache: npm
- name: Install
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index 42e9399..bfcd51b 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -14,6 +14,12 @@ N.B. See changelogs for individual packages, where most change will occur:
This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
+## [0.10.4] - 2025-03-06
+
+### Fixed
+
+- Ensured that the registry is explicitly set, to ensure that [`@actions/setup-node`](https://github.com/actions/setup-node) honours the `NODE_AUTH_TOKEN`
+
## [0.10.3] - 2025-02-27
### Fixed
diff --git a/package.json b/package.json
index a2992c6..540f361 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@asos/web-toggle-point",
- "version": "0.10.3",
+ "version": "0.10.4",
"repository": "git@github.com:asos/web-toggle-point.git",
"homepage": "https://asos.github.io/web-toggle-point/",
"license": "MIT",
From e942cde472bd47b769bfeea78d4b702b4d3a4088 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 29 Jul 2025 21:01:45 +0100
Subject: [PATCH 05/44] Extract portions of load strategies update and apply
separately
---
docs/CHANGELOG.md | 7 +
eslint.config.mjs | 10 +-
examples/express/docs/CHANGELOG.md | 6 +
examples/express/package.json | 2 +-
.../express/src/routes/animals/middleware.js | 1 -
examples/next/docs/CHANGELOG.md | 6 +
examples/next/next.config.mjs | 4 +-
examples/serve/docs/CHANGELOG.md | 8 +-
.../listExtractionFromPathSegment.js | 6 +-
.../singleFilenameDottedSegment.js | 6 +-
.../src/toggleHandlers/singlePathSegment.js | 6 +-
package-lock.json | 53 +---
package.json | 4 +-
packages/webpack/docs/CHANGELOG.md | 15 ++
packages/webpack/package.json | 13 +-
.../fillDefaultOptionalValues.js | 27 ++
.../fillDefaultOptionalValues.test.js | 84 ++++++
.../src/plugins/togglePointInjection/index.js | 17 +-
.../togglePointInjection/index.test.js | 241 +++++++++---------
.../togglePointInjection/integration.test.js | 6 +-
.../plugins/togglePointInjection/logger.js | 8 +-
.../togglePointInjection/logger.test.js | 13 +-
.../fillDefaultOptionalValues.js | 13 -
.../fillDefaultOptionalValues.test.js | 74 ------
.../processPointCuts/index.js | 5 +-
.../processPointCuts/index.test.js | 20 +-
.../processVariantFiles/index.js | 18 +-
.../processVariantFiles/index.test.js | 128 +++++-----
.../processVariantFiles/linkJoinPoints.js | 13 +
.../linkJoinPoints.test.js | 109 ++++++++
.../resolveJoinPoints/index.js | 55 ++--
.../resolveJoinPoints/index.test.js | 21 +-
.../setupSchemeModules/generateJoinPoint.js | 20 --
.../generateJoinPoint.test.js | 47 ----
.../generateJoinPoint/createVariantPathMap.js | 5 +
.../createVariantPathMap.test.js | 11 +
.../generateJoinPoint/importCodeGenerator.js | 15 ++
.../importCodeGenerator.test.js | 44 ++++
.../generateJoinPoint/index.js | 18 ++
.../generateJoinPoint/index.test.js | 51 ++++
.../setupSchemeModules/generatePointCut.js | 4 +-
.../generatePointCut.test.js | 6 +-
.../setupSchemeModules/index.js | 8 +-
.../setupSchemeModules/index.test.js | 21 +-
.../pathSegmentToggleHandler.js | 18 +-
.../pathSegmentToggleHandler.test.js | 30 ++-
packages/webpack/test/test-utils.js | 1 -
47 files changed, 770 insertions(+), 528 deletions(-)
create mode 100644 packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.test.js
delete mode 100644 packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.js
delete mode 100644 packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.test.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.test.js
delete mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.js
delete mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.test.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.test.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.test.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.js
create mode 100644 packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.test.js
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index af73a0d..9ce5f67 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -14,6 +14,13 @@ N.B. See changelogs for individual packages, where most change will occur:
This log covers the [monorepo](https://en.wikipedia.org/wiki/Monorepo).
+## [0.10.7] - 2025-07-29
+
+### Changed
+
+- updated to `0.11.0` of [`eslint-plugin-workspaces`](https://github.com/joshuajaco/eslint-plugin-workspaces) after [addition of ESLint9 support](https://github.com/joshuajaco/eslint-plugin-workspaces/commit/af855c3a3d8069366d4446747e91828ddf7560c6)
+ - update `eslint.config.mjs` to utilise flat config
+
## [0.10.6] - 2025-07-14
### Fixed
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 93f947b..3ffc16a 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -2,19 +2,13 @@ import asosConfig from "./peripheral/eslint-config-asosconfig/index.js";
import globals from "globals";
import jsdoc from "eslint-plugin-jsdoc";
import markdown from "@eslint/markdown";
-import { FlatCompat } from "@eslint/eslintrc";
-import path from "path";
-import { fileURLToPath } from "url";
+import workspaces from "eslint-plugin-workspaces";
const scripts = ["*.{js,mjs}", "**/*.{js,mjs}"];
const markDowns = ["*.md", "**/*.md"];
-const compat = new FlatCompat({
- baseDirectory: path.dirname(fileURLToPath(import.meta.url))
-});
-
export default [
- ...compat.extends("plugin:workspaces/recommended"),
+ workspaces.configs["flat/recommended"],
...asosConfig.map((config) => ({
files: scripts,
ignores: ["**/docs/**", "**/danger/**"],
diff --git a/examples/express/docs/CHANGELOG.md b/examples/express/docs/CHANGELOG.md
index af7bab2..03a6019 100644
--- a/examples/express/docs/CHANGELOG.md
+++ b/examples/express/docs/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.6] - 2025-07-29
+
+### Fixed
+
+- removed "Vary" header from "animals" example, the page is meant to be un-cacheable, and the value was wrong in any case
+
## [0.2.5] - 2025-05-27
### Changed
diff --git a/examples/express/package.json b/examples/express/package.json
index 07a30e8..4894627 100644
--- a/examples/express/package.json
+++ b/examples/express/package.json
@@ -1,6 +1,6 @@
{
"name": "web-toggle-point-express-example",
- "version": "0.2.5",
+ "version": "0.2.6",
"type": "module",
"engines": {
"node": ">=20.6.0"
diff --git a/examples/express/src/routes/animals/middleware.js b/examples/express/src/routes/animals/middleware.js
index ef8eae2..ea8e1b7 100644
--- a/examples/express/src/routes/animals/middleware.js
+++ b/examples/express/src/routes/animals/middleware.js
@@ -8,7 +8,6 @@ const contextMiddleware = (request, response, scopeCallBack) => {
response.status(StatusCodes.BAD_REQUEST).end();
return;
}
- response.header("Vary", version);
featuresStore.useValue({ value: { version }, scopeCallBack });
};
diff --git a/examples/next/docs/CHANGELOG.md b/examples/next/docs/CHANGELOG.md
index 91c3ed8..e918e3c 100644
--- a/examples/next/docs/CHANGELOG.md
+++ b/examples/next/docs/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.5] - 2025-05-29
+
+### Changed
+
+- update to take supply static `webpackNormalModule` corresponding to webpack plugin [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-05-29)
+
## [0.2.4] - 2025-05-27
### Changed
diff --git a/examples/next/next.config.mjs b/examples/next/next.config.mjs
index 428a031..799b10b 100644
--- a/examples/next/next.config.mjs
+++ b/examples/next/next.config.mjs
@@ -1,5 +1,6 @@
import createMDX from "@next/mdx";
import remarkGfm from "remark-gfm";
+import webpackNormalModule from "next/dist/compiled/webpack/NormalModule.js";
/** @type {import('next').NextConfig} */
const nextConfig = {
@@ -17,8 +18,7 @@ const togglePointInjection = new TogglePointInjection({
]
}
],
- webpackNormalModule: async () =>
- (await import("next/dist/compiled/webpack/NormalModule.js")).default
+ webpackNormalModule
});
nextConfig.webpack = (config) => {
diff --git a/examples/serve/docs/CHANGELOG.md b/examples/serve/docs/CHANGELOG.md
index b3f8ea1..e2ca06f 100644
--- a/examples/serve/docs/CHANGELOG.md
+++ b/examples/serve/docs/CHANGELOG.md
@@ -5,11 +5,17 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.2.7] - 2025-07-29
+
+### Changed
+
+- updated toggle handlers to take a `variantPathMap` corresponding to webpack [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-05-29)
+
## [0.2.6] - 2025-07-14
### Changed
-- updated to use `variantGlobs` array, with updated webpack plugin [0.8.0][version 0.8.0](../../../packages/webpack/docs/CHANGELOG.md#080---2025-05-27)
+- updated to use `variantGlobs` array, with updated webpack plugin [version 0.8.0](../../../packages/webpack/docs/CHANGELOG.md#080---2025-05-27)
## [0.2.5] - 2025-07-14
diff --git a/examples/serve/src/toggleHandlers/listExtractionFromPathSegment.js b/examples/serve/src/toggleHandlers/listExtractionFromPathSegment.js
index 6fc9234..e8189b7 100644
--- a/examples/serve/src/toggleHandlers/listExtractionFromPathSegment.js
+++ b/examples/serve/src/toggleHandlers/listExtractionFromPathSegment.js
@@ -1,9 +1,9 @@
-export default ({ togglePoint, joinPoint, variants }) => {
- const featuresMap = variants.keys().reduce((map, key) => {
+export default ({ togglePoint, joinPoint, variantPathMap }) => {
+ const featuresMap = variantPathMap.keys().reduce((map, key) => {
const [, , value] = key.split("/");
const list = value.split(",");
for (const value of list) {
- map.set(value, variants(key));
+ map.set(value, variantPathMap.get(key));
}
return map;
}, new Map());
diff --git a/examples/serve/src/toggleHandlers/singleFilenameDottedSegment.js b/examples/serve/src/toggleHandlers/singleFilenameDottedSegment.js
index d9dc3bc..2d9a6a3 100644
--- a/examples/serve/src/toggleHandlers/singleFilenameDottedSegment.js
+++ b/examples/serve/src/toggleHandlers/singleFilenameDottedSegment.js
@@ -1,8 +1,8 @@
-export default ({ togglePoint, joinPoint, variants }) => {
+export default ({ togglePoint, joinPoint, variantPathMap }) => {
const featuresMap = new Map();
- for (const key of variants.keys()) {
+ for (const key of variantPathMap.keys()) {
const [, , value] = key.split(".");
- featuresMap.set(value, variants(key));
+ featuresMap.set(value, variantPathMap.get(key));
}
return togglePoint(joinPoint, featuresMap);
};
diff --git a/examples/serve/src/toggleHandlers/singlePathSegment.js b/examples/serve/src/toggleHandlers/singlePathSegment.js
index 9cf4f2d..7a72925 100644
--- a/examples/serve/src/toggleHandlers/singlePathSegment.js
+++ b/examples/serve/src/toggleHandlers/singlePathSegment.js
@@ -1,8 +1,8 @@
-export default ({ togglePoint, joinPoint, variants }) => {
+export default ({ togglePoint, joinPoint, variantPathMap }) => {
const featuresMap = new Map();
- for (const key of variants.keys()) {
+ for (const key of variantPathMap.keys()) {
const [, value] = key.split("/");
- featuresMap.set(value, variants(key));
+ featuresMap.set(value, variantPathMap.get(key));
}
return togglePoint(joinPoint, featuresMap);
};
diff --git a/package-lock.json b/package-lock.json
index df4b789..3929385 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@asos/web-toggle-point",
- "version": "0.10.6",
+ "version": "0.10.7",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@asos/web-toggle-point",
- "version": "0.10.6",
+ "version": "0.10.7",
"license": "MIT",
"workspaces": [
"packages/features",
@@ -42,7 +42,7 @@
"eslint-plugin-jest-formatting": "^3.1.0",
"eslint-plugin-jsdoc": "^50.5.0",
"eslint-plugin-prettier": "^5.2.1",
- "eslint-plugin-workspaces": "^0.10.1",
+ "eslint-plugin-workspaces": "^0.11.0",
"globals": "^15.12.0",
"jsdoc": "^4.0.4",
"lint-staged": "^15.2.10",
@@ -57,7 +57,7 @@
},
"examples/express": {
"name": "web-toggle-point-express-example",
- "version": "0.2.5",
+ "version": "0.2.6",
"dependencies": {
"@asos/web-toggle-point-features": "file:../../packages/features",
"@asos/web-toggle-point-react-pointcuts": "file:../../packages/react-pointcuts",
@@ -6048,7 +6048,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001690",
+ "version": "1.0.30001731",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
+ "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
"funding": [
{
"type": "opencollective",
@@ -8518,11 +8520,13 @@
}
},
"node_modules/eslint-plugin-workspaces": {
- "version": "0.10.1",
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-workspaces/-/eslint-plugin-workspaces-0.11.0.tgz",
+ "integrity": "sha512-1Ol5QoV+IDBt/YiGCAXWKccKI3AAUSQUmaz0cw0at/MjgEPHvCQAkrv5U2p0C3YInd4sOfBzmyumhWFl6n6INQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "find-workspaces": "^0.3.0"
+ "find-workspaces": "^0.3.1"
}
},
"node_modules/eslint-scope": {
@@ -16576,30 +16580,6 @@
"@babel/runtime": "^7.8.4"
}
},
- "node_modules/regexgen": {
- "version": "1.3.0",
- "license": "MIT",
- "dependencies": {
- "jsesc": "^2.3.0",
- "regenerate": "^1.3.2"
- },
- "bin": {
- "regexgen": "bin/cli.js"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/regexgen/node_modules/jsesc": {
- "version": "2.5.2",
- "license": "MIT",
- "bin": {
- "jsesc": "bin/jsesc"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/regexp.prototype.flags": {
"version": "1.5.3",
"license": "MIT",
@@ -19936,12 +19916,11 @@
},
"packages/webpack": {
"name": "@asos/web-toggle-point-webpack",
- "version": "0.8.0",
+ "version": "0.9.0",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
- "fast-glob": "^3.2.12",
- "regexgen": "^1.3.0"
+ "fast-glob": "^3.2.12"
},
"devDependencies": {
"@rollup/plugin-babel": "^6.0.2",
@@ -19963,13 +19942,7 @@
"webpack-test-utils": "^2.1.0"
},
"peerDependencies": {
- "next": ">14",
"webpack": ">=5.70"
- },
- "peerDependenciesMeta": {
- "next": {
- "optional": true
- }
}
},
"peripheral/babel-preset-asos": {
diff --git a/package.json b/package.json
index c59b22c..1bd3fc1 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@asos/web-toggle-point",
- "version": "0.10.6",
+ "version": "0.10.7",
"repository": "git@github.com:asos/web-toggle-point.git",
"homepage": "https://asos.github.io/web-toggle-point/",
"license": "MIT",
@@ -51,7 +51,7 @@
"eslint-plugin-jest-formatting": "^3.1.0",
"eslint-plugin-jsdoc": "^50.5.0",
"eslint-plugin-prettier": "^5.2.1",
- "eslint-plugin-workspaces": "^0.10.1",
+ "eslint-plugin-workspaces": "^0.11.0",
"globals": "^15.12.0",
"jsdoc": "^4.0.4",
"lint-staged": "^15.2.10",
diff --git a/packages/webpack/docs/CHANGELOG.md b/packages/webpack/docs/CHANGELOG.md
index 8673a3c..66419da 100644
--- a/packages/webpack/docs/CHANGELOG.md
+++ b/packages/webpack/docs/CHANGELOG.md
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.9.0] - 2025-07-29
+
+### Changed
+
+- consolidated setting of default optional values
+- changed `variants` array on join point data structure to a `Map` of relative to absolute path as `variantPathMap`
+- move away from webpack `import.meta.webpackContext` when generating join points, construct a `Map` manually instead
+ - add linking of join points, to supplant the functionality previously provided by `import.meta.webpackContext`
+- updated win32 path replacement, can effectively no-op on posix systems
+
+### Fixed
+
+- removed "next" peer dependency, this needn't be explicit
+- ensured files that cannot be resolved (by [enhanced-resolve](https://github.com/webpack/enhanced-resolve/)), for whatever reason, don't break the build
+
## [0.8.0] - 2025-05-27
### Changed
diff --git a/packages/webpack/package.json b/packages/webpack/package.json
index 093b158..02afc72 100644
--- a/packages/webpack/package.json
+++ b/packages/webpack/package.json
@@ -1,7 +1,7 @@
{
"name": "@asos/web-toggle-point-webpack",
"description": "toggle point webpack plugin",
- "version": "0.8.0",
+ "version": "0.9.0",
"license": "MIT",
"type": "module",
"main": "./lib/main.cjs",
@@ -35,8 +35,7 @@
},
"dependencies": {
"@babel/runtime": "^7.26.0",
- "fast-glob": "^3.2.12",
- "regexgen": "^1.3.0"
+ "fast-glob": "^3.2.12"
},
"devDependencies": {
"@rollup/plugin-babel": "^6.0.2",
@@ -58,12 +57,6 @@
"webpack-test-utils": "^2.1.0"
},
"peerDependencies": {
- "webpack": ">=5.70",
- "next": ">14"
- },
- "peerDependenciesMeta": {
- "next": {
- "optional": true
- }
+ "webpack": ">=5.70"
}
}
diff --git a/packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.js b/packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.js
new file mode 100644
index 0000000..a23fbbe
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.js
@@ -0,0 +1,27 @@
+import { posix, basename } from "path";
+import webpack from "webpack";
+
+const fillDefaultPointcutValues = (pointCut) => {
+ const {
+ variantGlobs = ["./**/__variants__/*/*/!(*.test).{js,jsx,ts,tsx}"],
+ joinPointResolver = (variantPath) =>
+ posix.resolve(variantPath, ...Array(4).fill(".."), basename(variantPath)),
+ toggleHandler = "@asos/web-toggle-point-webpack/pathSegmentToggleHandler"
+ } = pointCut;
+ return {
+ ...pointCut,
+ variantGlobs,
+ joinPointResolver,
+ toggleHandler
+ };
+};
+
+const fillDefaultOptionalValues = (options) => {
+ return {
+ webpackNormalModule: webpack.NormalModule,
+ ...options,
+ pointCuts: options.pointCuts.map(fillDefaultPointcutValues)
+ };
+};
+
+export default fillDefaultOptionalValues;
diff --git a/packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.test.js b/packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.test.js
new file mode 100644
index 0000000..7e5a2f4
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/fillDefaultOptionalValues.test.js
@@ -0,0 +1,84 @@
+import webpack from "webpack";
+import fillDefaultOptionalValues from "./fillDefaultOptionalValues.js";
+
+jest.mock("webpack", () => ({ NormalModule: Symbol("test-normal-module") }));
+
+describe("fillDefaultOptionalValues", () => {
+ let result;
+
+ const makeDefaultJoinPointResolverAssertions = () => {
+ describe("when the joinPointResolver is called", () => {
+ it("should return a path that is the same as the variantPath, but with the last 3 directories removed", () => {
+ const variantPath =
+ "/test-folder/test-sub-folder/test-sub-folder/test-sub-folder/test-variant";
+ const joinPointPath = result.joinPointResolver(variantPath);
+ expect(joinPointPath).toEqual("/test-folder/test-variant");
+ });
+ });
+ };
+
+ const variantGlobs = Symbol("test-variant-globs");
+ const joinPointResolver = Symbol("test-join-point-resolver");
+
+ const defaultVariantGlobs = [
+ "./**/__variants__/*/*/!(*.test).{js,jsx,ts,tsx}"
+ ];
+ const defaultJoinPointResolver = expect.any(Function);
+ const defaultToggleHandler =
+ "@asos/web-toggle-point-webpack/pathSegmentToggleHandler";
+ const toggleHandler = Symbol("test-toggle-handler");
+ const webpackNormalModule = Symbol("test-webpack-normal-module");
+
+ describe("when configuring the plugin with a supplied webpackNormalModule", () => {
+ beforeEach(() => {
+ result = fillDefaultOptionalValues({
+ webpackNormalModule,
+ pointCuts: []
+ });
+ });
+
+ it("should return the supplied webpackNormalModule", () => {
+ expect(result.webpackNormalModule).toBe(webpackNormalModule);
+ });
+ });
+
+ describe("when configuring the plugin without supplying a webpackNormalModule", () => {
+ beforeEach(() => {
+ result = fillDefaultOptionalValues({
+ pointCuts: []
+ });
+ });
+
+ it("should return the NormalModule from the webpack import", () => {
+ expect(result.webpackNormalModule).toBe(webpack.NormalModule);
+ });
+ });
+
+ describe.each`
+ variantGlobs | joinPointResolver | toggleHandler | description | expectation
+ ${undefined} | ${undefined} | ${undefined} | ${"nothing"} | ${{ variantGlobs: defaultVariantGlobs, joinPointResolver: defaultJoinPointResolver, toggleHandler: defaultToggleHandler }}
+ ${variantGlobs} | ${undefined} | ${undefined} | ${"a variantGlob, but nothing else"} | ${{ variantGlobs, joinPointResolver: defaultJoinPointResolver, toggleHandler: defaultToggleHandler }}
+ ${variantGlobs} | ${joinPointResolver} | ${undefined} | ${"a variantGlob and a join point resolver"} | ${{ variantGlobs, joinPointResolver, toggleHandler: defaultToggleHandler }}
+ ${undefined} | ${joinPointResolver} | ${undefined} | ${"a joinPointResolver, but nothing else"} | ${{ variantGlobs: defaultVariantGlobs, joinPointResolver, toggleHandler: defaultToggleHandler }}
+ ${undefined} | ${undefined} | ${toggleHandler} | ${"a toggle handler "} | ${{ variantGlobs: defaultVariantGlobs, joinPointResolver: defaultJoinPointResolver, toggleHandler }}
+ ${variantGlobs} | ${undefined} | ${toggleHandler} | ${"a toggle handler and a variantGlob, but nothing else"} | ${{ variantGlobs, joinPointResolver: defaultJoinPointResolver, toggleHandler }}
+ ${variantGlobs} | ${joinPointResolver} | ${toggleHandler} | ${"a toggle handler, a variantGlob and a join point resolver"} | ${{ variantGlobs, joinPointResolver, toggleHandler }}
+ ${undefined} | ${joinPointResolver} | ${toggleHandler} | ${"a toggle handler and a joinPointResolver, but nothing else"} | ${{ variantGlobs: defaultVariantGlobs, joinPointResolver, toggleHandler }}
+ `(
+ "when configuring pointCuts, supplying $description",
+ // eslint-disable-next-line no-unused-vars
+ ({ expectation, description, ...pointCut }) => {
+ beforeEach(async () => {
+ result = fillDefaultOptionalValues({ pointCuts: [pointCut] });
+ });
+
+ it("should fill the defaults", () => {
+ expect(result.pointCuts[0]).toEqual(expectation);
+ });
+
+ if (!joinPointResolver) {
+ makeDefaultJoinPointResolverAssertions();
+ }
+ }
+ );
+});
diff --git a/packages/webpack/src/plugins/togglePointInjection/index.js b/packages/webpack/src/plugins/togglePointInjection/index.js
index 12d32da..c78aa96 100644
--- a/packages/webpack/src/plugins/togglePointInjection/index.js
+++ b/packages/webpack/src/plugins/togglePointInjection/index.js
@@ -1,11 +1,12 @@
import processPointCuts from "./processPointCuts/index.js";
import Logger from "./logger.js";
-import { win32, posix } from "path";
+import { sep, posix } from "path";
import { PLUGIN_NAME } from "./constants.js";
import resolveJoinPoints from "./resolveJoinPoints/index.js";
import setupSchemeModules from "./setupSchemeModules/index.js";
import { validate } from "schema-utils";
import schema from "./schema.json";
+import fillDefaultOptionalValues from "./fillDefaultOptionalValues.js";
/**
* Toggle Point Injection Plugin
@@ -21,8 +22,8 @@ class TogglePointInjection {
* @param {string} options.pointCuts[].togglePointModule path, from root of the compilation, of where the toggle point sits. Or a resolvable node_module.
* @param {string[]} [options.pointCuts[].variantGlobs=[.\/**\/__variants__/*\/*\/!(*.test).{js,jsx,ts,tsx}]] {@link https://en.wikipedia.org/wiki/Glob_(programming)|Globs} to identified variant modules. The plugin uses {@link https://github.com/mrmlnc/fast-glob|fast-glob} under the hood, so supports any glob that it does.
* @param {function} [options.pointCuts[].joinPointResolver=(variantPath) => path.posix.resolve(variantPath, "../../../..", path.basename(variantPath))] A function that takes the path to a variant module and returns a join point / base module. N.B. This is executed at build-time, so cannot use run-time context. It should use posix path segments, so on Windows be sure to use path.posix.resolve.
- * @param {string} [options.pointCuts[].toggleHandler] Path to a toggle handler that unpicks a {@link https://webpack.js.org/api/module-methods/#requirecontext|require.context} containing potential variants, passing that plus a joint point module to a toggle point function. If not provided, the plugin will use a default handler that processes folder names into a tree held in a Map. Leaf nodes of the tree are the variant modules.
- * @param {function} [options.webpackNormalModule] A function that returns the Webpack NormalModule class. This is required for Next.js, as it does not expose the NormalModule class directly
+ * @param {string} [options.pointCuts[].toggleHandler='@asos/web-toggle-point-webpack/pathSegmentToggleHandler'] a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_features_into_your_script|module specifier} pointing to a toggle handler, that takes a toggle point, a Map of relative paths to potential variants, and a join point. If not provided, the plugin will use a default handler that processes folder names into a tree held in a Map.
+ * @param {function} [options.webpackNormalModule] A reference to the Webpack NormalModule class. This is required for Next.js, as it does not expose the NormalModule class directly
* @returns {external:Webpack.WebpackPluginInstance} WebpackPluginInstance
* @example N.B. forward slashes are escaped in the glob, due to JSDoc shortcomings, but in reality should be un-escaped
* const plugin = new TogglePointInjection({
@@ -44,23 +45,19 @@ class TogglePointInjection {
*/
constructor(options) {
validate(schema, options, { name: PLUGIN_NAME, baseDataPath: "options" });
- this.options = {
- webpackNormalModule: async () =>
- (await import("webpack")).default.NormalModule,
- ...options
- };
+ this.options = fillDefaultOptionalValues(options);
}
apply(compiler) {
let NormalModule, joinPointFiles, warnings, appRoot;
compiler.hooks.beforeCompile.tapPromise(PLUGIN_NAME, async () => {
- appRoot = compiler.context.replaceAll(win32.sep, posix.sep);
+ appRoot = compiler.context.replaceAll(sep, posix.sep);
({ joinPointFiles, warnings } = await processPointCuts({
appRoot,
fileSystem: compiler.inputFileSystem,
options: this.options
}));
- NormalModule = await this.options.webpackNormalModule();
+ NormalModule = await this.options.webpackNormalModule;
});
compiler.hooks.compilation.tap(
diff --git a/packages/webpack/src/plugins/togglePointInjection/index.test.js b/packages/webpack/src/plugins/togglePointInjection/index.test.js
index 472063b..d2db6bb 100644
--- a/packages/webpack/src/plugins/togglePointInjection/index.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/index.test.js
@@ -4,7 +4,7 @@ import { PLUGIN_NAME } from "./constants.js";
import resolveJoinPoints from "./resolveJoinPoints/index.js";
import setupSchemeModules from "./setupSchemeModules/index.js";
import TogglePointInjection from "./index.js";
-import webpack from "webpack";
+import fillDefaultOptionalValues from "./fillDefaultOptionalValues.js";
import { validate } from "schema-utils";
import schema from "./schema.json";
@@ -20,9 +20,15 @@ jest.mock("./constants", () => ({
jest.mock("./processPointCuts/index.js", () => jest.fn());
jest.mock("./resolveJoinPoints/index.js", () => jest.fn());
jest.mock("./setupSchemeModules/index.js", () => jest.fn());
-jest.mock("webpack", () => ({ NormalModule: Symbol("test-normal-module") }));
jest.mock("schema-utils", () => ({ validate: jest.fn() }));
jest.mock("./schema.json", () => Symbol("test-json"));
+const mockNormalModule = Symbol("test-normal-module");
+jest.mock("./fillDefaultOptionalValues.js", () =>
+ jest.fn((options) => ({
+ ...options,
+ webpackNormalModule: mockNormalModule
+ }))
+);
describe("togglePointInjection", () => {
let togglePointInjection, compiler, options;
@@ -40,162 +46,145 @@ describe("togglePointInjection", () => {
};
});
- const makeCommonAssertions = (NormalModule) => {
- it("should validate the supplied options", () => {
- expect(validate).toHaveBeenCalledWith(
- schema,
- options,
- expect.objectContaining({ name: PLUGIN_NAME, baseDataPath: "options" })
- );
- });
-
- it("should tap into the beforeCompile event, indicating the plugin name", () => {
- expect(compiler.hooks.beforeCompile.tapPromise).toHaveBeenCalledWith(
- PLUGIN_NAME,
- expect.any(Function)
- );
- });
-
- it("should tap into the compilation event, indicating the plugin name", () => {
- expect(compiler.hooks.compilation.tap).toHaveBeenCalledWith(
- PLUGIN_NAME,
- expect.any(Function)
- );
+ describe("when a webpackNormalModule option is not supplied", () => {
+ beforeEach(() => {
+ options = { pointCuts };
+ togglePointInjection = new TogglePointInjection(options);
});
- describe("when the beforeCompile event is triggered", () => {
- let beforeCompileCallback, resolve, result;
- const warnings = Symbol("test-warnings");
- const compilation = Symbol("test-compilation");
- const normalModuleFactory = Symbol("test-normal-module-factory");
-
+ describe("when applying to a compiler", () => {
beforeEach(() => {
- processPointCuts.mockReturnValue(
- new Promise((res) => {
- resolve = res;
+ togglePointInjection.apply(compiler);
+ });
+
+ it("should validate the supplied options", () => {
+ expect(validate).toHaveBeenCalledWith(
+ schema,
+ options,
+ expect.objectContaining({
+ name: PLUGIN_NAME,
+ baseDataPath: "options"
})
);
- [, beforeCompileCallback] =
- compiler.hooks.beforeCompile.tapPromise.mock.lastCall;
- result = beforeCompileCallback();
});
- it("should process the supplied point cuts, returning only when processed", () => {
- expect(processPointCuts).toHaveBeenCalledWith({
- appRoot: compiler.context,
- fileSystem: compiler.inputFileSystem,
- options: togglePointInjection.options
- });
+ it("should fill in default optional values", () => {
+ expect(fillDefaultOptionalValues).toHaveBeenCalledWith(options);
});
- const makeCommonAssertions = () => {
- it("should create a logger for the compilation", () => {
- expect(Logger).toHaveBeenCalledWith(compilation);
- });
+ it("should tap into the beforeCompile event, indicating the plugin name", () => {
+ expect(compiler.hooks.beforeCompile.tapPromise).toHaveBeenCalledWith(
+ PLUGIN_NAME,
+ expect.any(Function)
+ );
+ });
+
+ it("should tap into the compilation event, indicating the plugin name", () => {
+ expect(compiler.hooks.compilation.tap).toHaveBeenCalledWith(
+ PLUGIN_NAME,
+ expect.any(Function)
+ );
+ });
- it("should log any warnings", () => {
- expect(Logger.mock.instances[0].logWarnings).toHaveBeenCalledWith(
- warnings
+ describe("when the beforeCompile event is triggered", () => {
+ let beforeCompileCallback, resolve, result;
+ const warnings = Symbol("test-warnings");
+ const compilation = Symbol("test-compilation");
+ const normalModuleFactory = Symbol("test-normal-module-factory");
+
+ beforeEach(() => {
+ processPointCuts.mockReturnValue(
+ new Promise((res) => {
+ resolve = res;
+ })
);
+ [, beforeCompileCallback] =
+ compiler.hooks.beforeCompile.tapPromise.mock.lastCall;
+ result = beforeCompileCallback();
});
- };
-
- describe("when the point cuts are processed, and some are found", () => {
- const joinPointFiles = new Set([Symbol("test-join-point-file")]);
- beforeEach(async () => {
- resolve({ joinPointFiles, warnings });
- await result;
+ it("should process the supplied point cuts, returning only when processed", () => {
+ expect(processPointCuts).toHaveBeenCalledWith({
+ appRoot: compiler.context,
+ fileSystem: compiler.inputFileSystem,
+ options: togglePointInjection.options
+ });
});
- describe("when the compilation event is triggered", () => {
- beforeEach(() => {
- const [, compilationCallback] =
- compiler.hooks.compilation.tap.mock.lastCall;
- compilationCallback(compilation, { normalModuleFactory });
+ const makeCommonAssertions = () => {
+ it("should create a logger for the compilation", () => {
+ expect(Logger).toHaveBeenCalledWith(compilation);
});
- makeCommonAssertions();
-
- it("should log the join points", () => {
- expect(Logger.mock.instances[0].logJoinPoints).toHaveBeenCalledWith(
- joinPointFiles
+ it("should log any warnings", () => {
+ expect(Logger.mock.instances[0].logWarnings).toHaveBeenCalledWith(
+ warnings
);
});
+ };
- it("should set up scheme modules", () => {
- expect(setupSchemeModules).toHaveBeenCalledWith({
- NormalModule,
- compilation,
- joinPointFiles,
- pointCuts
- });
- });
+ describe("when the point cuts are processed, and some are found", () => {
+ const joinPointFiles = new Set([Symbol("test-join-point-file")]);
- it("should resolve the join points", () => {
- expect(resolveJoinPoints).toHaveBeenCalledWith({
- compilation,
- appRoot: compiler.context,
- normalModuleFactory,
- joinPointFiles
- });
+ beforeEach(async () => {
+ resolve({ joinPointFiles, warnings });
+ await result;
});
- });
- });
-
- describe("when the point cuts are processed, and none are found", () => {
- beforeEach(async () => {
- resolve({ joinPointFiles: [], warnings });
- await result;
- });
- describe("when the compilation event is triggered", () => {
- beforeEach(() => {
- const [, compilationCallback] =
- compiler.hooks.compilation.tap.mock.lastCall;
- compilationCallback(compilation, {
- normalModuleFactory
+ describe("when the compilation event is triggered", () => {
+ beforeEach(() => {
+ const [, compilationCallback] =
+ compiler.hooks.compilation.tap.mock.lastCall;
+ compilationCallback(compilation, { normalModuleFactory });
});
- });
- makeCommonAssertions();
- });
- });
- });
- };
+ makeCommonAssertions();
- describe("when a webpackNormalModule option is not supplied", () => {
- beforeEach(() => {
- options = { pointCuts };
- togglePointInjection = new TogglePointInjection(options);
- });
+ it("should log the join points", () => {
+ expect(
+ Logger.mock.instances[0].logJoinPoints
+ ).toHaveBeenCalledWith(joinPointFiles);
+ });
- describe("when applying to a compiler", () => {
- beforeEach(() => {
- togglePointInjection.apply(compiler);
- });
+ it("should set up scheme modules", () => {
+ expect(setupSchemeModules).toHaveBeenCalledWith({
+ NormalModule: mockNormalModule,
+ compilation,
+ joinPointFiles,
+ pointCuts
+ });
+ });
- makeCommonAssertions(webpack.NormalModule);
- });
- });
+ it("should resolve the join points", () => {
+ expect(resolveJoinPoints).toHaveBeenCalledWith({
+ compilation,
+ appRoot: compiler.context,
+ normalModuleFactory,
+ joinPointFiles
+ });
+ });
+ });
+ });
- describe("when a webpackNormalModule option is supplied (primarily for NextJs users to get around the fact that webpack is pre-bundled)", () => {
- const MockNormalModule = Symbol("test-normal-module");
+ describe("when the point cuts are processed, and none are found", () => {
+ beforeEach(async () => {
+ resolve({ joinPointFiles: [], warnings });
+ await result;
+ });
- beforeEach(() => {
- options = {
- pointCuts,
- webpackNormalModule: async () => MockNormalModule
- };
- togglePointInjection = new TogglePointInjection(options);
- });
+ describe("when the compilation event is triggered", () => {
+ beforeEach(() => {
+ const [, compilationCallback] =
+ compiler.hooks.compilation.tap.mock.lastCall;
+ compilationCallback(compilation, {
+ normalModuleFactory
+ });
+ });
- describe("when applying to a compiler", () => {
- beforeEach(() => {
- togglePointInjection.apply(compiler);
+ makeCommonAssertions();
+ });
+ });
});
-
- makeCommonAssertions(MockNormalModule);
});
});
});
diff --git a/packages/webpack/src/plugins/togglePointInjection/integration.test.js b/packages/webpack/src/plugins/togglePointInjection/integration.test.js
index d28aa06..07ec825 100644
--- a/packages/webpack/src/plugins/togglePointInjection/integration.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/integration.test.js
@@ -1,6 +1,6 @@
import { build } from "webpack-test-utils";
import { readFile } from "fs/promises";
-import { resolve } from "path";
+import { posix } from "path";
import TogglePointInjection from "./index.js";
import { PLUGIN_NAME } from "./constants.js";
@@ -34,7 +34,7 @@ describe("togglePointInjection", () => {
fileSystem = {
"node_modules/@asos/web-toggle-point-webpack/pathSegmentToggleHandler":
await readFile(
- resolve(
+ posix.resolve(
__dirname,
"..",
"..",
@@ -102,7 +102,7 @@ describe("togglePointInjection", () => {
it("should log the fact that the toggle point was found", () => {
expect(getLogOfType("info")).toEqual(
- `Identified '${name}' point cut for join point '${modulesFolder}${moduleName}' with potential variants:\n./${variantsFolder}/${testFeature}/${testVariant}/${moduleName}`
+ `Identified '${name}' point cut for join point '${modulesFolder}${moduleName}' with potential variants:\n${modulesFolder}${variantsFolder}/${testFeature}/${testVariant}/${moduleName}`
);
});
diff --git a/packages/webpack/src/plugins/togglePointInjection/logger.js b/packages/webpack/src/plugins/togglePointInjection/logger.js
index 07ad8da..d85b6b5 100644
--- a/packages/webpack/src/plugins/togglePointInjection/logger.js
+++ b/packages/webpack/src/plugins/togglePointInjection/logger.js
@@ -11,14 +11,14 @@ class Logger {
for (const [
joinPoint,
{
- variants,
+ variantPathMap,
pointCut: { name }
}
] of joinPointFiles.entries()) {
this.#logger.info(
- `Identified '${name}' point cut for join point '${joinPoint}' with potential variants:\n${variants.join(
- "\n"
- )}`
+ `Identified '${name}' point cut for join point '${joinPoint}' with potential variants:\n${[
+ ...variantPathMap.values()
+ ].join("\n")}`
);
}
}
diff --git a/packages/webpack/src/plugins/togglePointInjection/logger.test.js b/packages/webpack/src/plugins/togglePointInjection/logger.test.js
index 915f876..6306bfe 100644
--- a/packages/webpack/src/plugins/togglePointInjection/logger.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/logger.test.js
@@ -21,12 +21,15 @@ describe("logger", () => {
describe("logJoinPoints", () => {
const pointCut = { name: "test-point-cut" };
const joinPointName = "test-join-point";
- const variants = ["test-variant-1", "test-variant-2"];
+ const variantPathMap = new Map([
+ ["test-key-1", "test-path-1"],
+ ["test-key-2", "test-key-2"]
+ ]);
const joinPointFiles = new Map([
[
joinPointName,
{
- variants,
+ variantPathMap,
pointCut: { name: "test-point-cut" }
}
]
@@ -40,9 +43,9 @@ describe("logger", () => {
expect(compilationLogger.info).toHaveBeenCalledWith(
`Identified '${
pointCut.name
- }' point cut for join point '${joinPointName}' with potential variants:\n${variants.join(
- "\n"
- )}`
+ }' point cut for join point '${joinPointName}' with potential variants:\n${Array.from(
+ variantPathMap.values()
+ ).join("\n")}`
);
});
});
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.js
deleted file mode 100644
index fecdcd5..0000000
--- a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { posix, basename } from "path";
-
-const fillPointCutDefaults = (pointCut) => {
- const {
- variantGlobs = ["./**/__variants__/*/*/!(*.test).{js,jsx,ts,tsx}"],
- joinPointResolver = (variantPath) =>
- posix.resolve(variantPath, ...Array(4).fill(".."), basename(variantPath))
- } = pointCut;
-
- return { variantGlobs, joinPointResolver };
-};
-
-export default fillPointCutDefaults;
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.test.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.test.js
deleted file mode 100644
index a199b19..0000000
--- a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/fillDefaultOptionalValues.test.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import fillPointCutDefaults from "./fillDefaultOptionalValues";
-
-describe("fillDefaultOptionalValues", () => {
- let result;
-
- const makeDefaultJoinPointResolverAssertions = () => {
- describe("when the joinPointResolver is called", () => {
- it("should return a path that is the same as the variantPath, but with the last 3 directories removed", () => {
- const variantPath =
- "/test-folder/test-sub-folder/test-sub-folder/test-sub-folder/test-variant";
- const joinPointPath = result.joinPointResolver(variantPath);
- expect(joinPointPath).toEqual("/test-folder/test-variant");
- });
- });
- };
-
- describe("when the point cut has no variantGlobs or joinPointResolver", () => {
- const pointCut = {};
-
- beforeEach(() => {
- result = fillPointCutDefaults(pointCut);
- });
-
- it("should fill the defaults", () => {
- expect(result).toEqual({
- variantGlobs: ["./**/__variants__/*/*/!(*.test).{js,jsx,ts,tsx}"],
- joinPointResolver: expect.any(Function)
- });
- });
-
- makeDefaultJoinPointResolverAssertions();
- });
-
- describe("when the point cut has a variantGlobs but no joinPointResolver", () => {
- const pointCut = { variantGlobs: Symbol("test-variant-globs") };
-
- beforeEach(() => {
- result = fillPointCutDefaults(pointCut);
- });
-
- it("should fill the defaults", () => {
- expect(result).toEqual({
- variantGlobs: pointCut.variantGlobs,
- joinPointResolver: expect.any(Function)
- });
- });
-
- makeDefaultJoinPointResolverAssertions();
- });
-
- describe("when the point cut has a joinPointResolver but no variantGlobs", () => {
- it("should return the supplied joinPointResolver and fill default variantGlobs", () => {
- const pointCut = {
- joinPointResolver: Symbol("test-join-point-resolver")
- };
- const result = fillPointCutDefaults(pointCut);
- expect(result).toEqual({
- variantGlobs: ["./**/__variants__/*/*/!(*.test).{js,jsx,ts,tsx}"],
- joinPointResolver: pointCut.joinPointResolver
- });
- });
- });
-
- describe("when the point cut has variantGlobs and a joinPointResolver", () => {
- it("should return the point cut supplied values", () => {
- const pointCut = {
- variantGlobs: Symbol("test-variant-glob"),
- joinPointResolver: Symbol("test-join-point-resolver")
- };
- const result = fillPointCutDefaults(pointCut);
- expect(result).toEqual(pointCut);
- });
- });
-});
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.js
index 503b057..ec0d590 100644
--- a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.js
+++ b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.js
@@ -1,6 +1,5 @@
import processVariantFiles from "./processVariantFiles/index.js";
import getVariantPaths from "./getVariantPaths.js";
-import fillDefaultOptionalValues from "./fillDefaultOptionalValues.js";
const processPointCuts = async ({
appRoot,
@@ -11,8 +10,7 @@ const processPointCuts = async ({
const configFiles = new Map();
const warnings = [];
for await (const pointCut of pointCuts.values()) {
- const { variantGlobs, joinPointResolver } =
- fillDefaultOptionalValues(pointCut);
+ const { variantGlobs } = pointCut;
const variantPaths = await getVariantPaths({
variantGlobs,
@@ -24,7 +22,6 @@ const processPointCuts = async ({
variantPaths,
joinPointFiles,
pointCut,
- joinPointResolver,
warnings,
configFiles,
fileSystem,
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.test.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.test.js
index 62768a2..71f9ecd 100644
--- a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/index.test.js
@@ -1,18 +1,11 @@
import processVariantFiles from "./processVariantFiles/index.js";
import getVariantPaths from "./getVariantPaths.js";
import processPointCuts from "./index.js";
-import fillDefaultOptionalValues from "./fillDefaultOptionalValues.js";
jest.mock("./processVariantFiles/index", () => jest.fn());
jest.mock("./getVariantPaths", () =>
jest.fn(() => Symbol("test-variant-files"))
);
-jest.mock("./fillDefaultOptionalValues", () =>
- jest.fn(() => ({
- variantGlobs: Symbol("test-variant-globs"),
- joinPointResolver: Symbol("test-join-point-resolver")
- }))
-);
describe("processPointCuts", () => {
const pointCuts = new Map([
@@ -34,16 +27,8 @@ describe("processPointCuts", () => {
}));
});
- it("should fill in default optional values for each point cut", () => {
- for (const pointCut of pointCutsValues) {
- expect(fillDefaultOptionalValues).toHaveBeenCalledWith(pointCut);
- }
- });
-
it("should get variant files for each of the point cuts", () => {
- for (const index of pointCutsValues.keys()) {
- const { variantGlobs } =
- fillDefaultOptionalValues.mock.results[index].value;
+ for (const { variantGlobs } of pointCutsValues.keys()) {
expect(getVariantPaths).toHaveBeenCalledWith({
variantGlobs,
appRoot,
@@ -55,13 +40,10 @@ describe("processPointCuts", () => {
it("should process the variant files, and keep a shared record of config files found between each point cut", () => {
for (const [index, pointCut] of pointCutsValues.entries()) {
const variantPaths = getVariantPaths.mock.results[index].value;
- const { joinPointResolver } =
- fillDefaultOptionalValues.mock.results[index].value;
expect(processVariantFiles).toHaveBeenCalledWith({
variantPaths,
joinPointFiles,
pointCut,
- joinPointResolver,
warnings,
configFiles: expect.any(Map),
fileSystem,
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.js
index 8d8e09a..33e4b5d 100644
--- a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.js
+++ b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.js
@@ -1,17 +1,20 @@
import { posix } from "path";
-import isJoinPointInvalid from "./isJoinPointInvalid";
+import isJoinPointInvalid from "./isJoinPointInvalid.js";
+import linkJoinPoints from "./linkJoinPoints.js";
const { parse, relative } = posix;
+const normalizeToRelativePath = (path, joinDirectory) =>
+ relative(joinDirectory, path).replace(/^([^./])/, "./$1");
+
const processVariantFiles = async ({
variantPaths,
joinPointFiles,
pointCut,
- joinPointResolver,
warnings,
...rest
}) => {
for (const variantPath of variantPaths) {
- const joinPointPath = joinPointResolver(variantPath);
+ const joinPointPath = pointCut.joinPointResolver(variantPath);
const { dir: directory, base: filename } = parse(joinPointPath);
if (!joinPointFiles.has(joinPointPath)) {
@@ -27,7 +30,7 @@ const processVariantFiles = async ({
}
joinPointFiles.set(joinPointPath, {
pointCut,
- variants: []
+ variantPathMap: new Map()
});
}
@@ -39,10 +42,11 @@ const processVariantFiles = async ({
continue;
}
- joinPointFile.variants.push(
- relative(directory, variantPath).replace(/^([^./])/, "./$1")
- );
+ const key = normalizeToRelativePath(variantPath, directory);
+ joinPointFile.variantPathMap.set(key, variantPath);
}
+
+ linkJoinPoints(joinPointFiles);
};
export default processVariantFiles;
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.test.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.test.js
index 1ff96c5..4a2a4c2 100644
--- a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/index.test.js
@@ -1,41 +1,37 @@
-import processVariantFiles from ".";
-import { memfs } from "memfs";
import { posix } from "path";
+import isJoinPointInvalid from "./isJoinPointInvalid.js";
+import linkJoinPoints from "./linkJoinPoints.js";
+import processVariantFiles from "./index.js";
+
const { resolve, join, sep } = posix;
+jest.mock("./linkJoinPoints.js", () => jest.fn());
+jest.mock("./isJoinPointInvalid.js", () => jest.fn());
+
describe("processVariantFiles", () => {
let joinPointFiles;
- const pointCut = { name: "test-point-cut" };
- const joinPointResolver = jest.fn();
+ const pointCut = { name: "test-point-cut", joinPointResolver: jest.fn() };
let warnings;
const variantFileGlob = "test-variant-*.*";
- const variantGlobs = [`/${variantFileGlob}`];
- const appRoot = "/test-app-root/";
const moduleFile = "test-module.js";
const joinPointFolder = "test-folder";
const joinPointPath = join(joinPointFolder, moduleFile);
- const { fs: fileSystem } = memfs({
- [`${appRoot}${joinPointPath}`]: "join point"
- });
+ const rest = { [Symbol("test-key")]: Symbol("test-value") };
- beforeEach(() => {
+ beforeEach(async () => {
+ jest.clearAllMocks();
warnings = [];
joinPointFiles = new Map();
});
- const act = async ({ variantPaths, configFiles }) => {
+ const act = async ({ variantPaths }) => {
await processVariantFiles({
variantPaths,
- configFiles,
joinPointFiles,
pointCut,
- joinPointResolver,
- variantGlobs,
warnings,
- name: moduleFile,
- fileSystem,
- appRoot
+ ...rest
});
};
@@ -61,14 +57,41 @@ describe("processVariantFiles", () => {
`(
"when given a variant path ($variantPath)",
({ variantPath, expectedVariant }) => {
+ const path = resolve(joinPointFolder, variantPath);
const variantPaths = new Set([resolve(joinPointFolder, variantPath)]);
- describe("when given a variant file that has no matching join point file", () => {
+ const makeCommonAssertions = () => {
+ it("should call the joinPointResolver with the path to the variant file", () => {
+ expect(pointCut.joinPointResolver).toHaveBeenCalledWith(path);
+ });
+
+ it("should call linkJoinPoints with the updated joinPointFiles", () => {
+ expect(linkJoinPoints).toHaveBeenCalledWith(joinPointFiles);
+ });
+ };
+
+ describe("when given a variant file that is not valid according to the configured config files", () => {
+ const filename = "test-not-matching-control";
+ const joinPointPath = join(joinPointFolder, filename);
+
beforeEach(async () => {
- joinPointResolver.mockReturnValue(
- join(joinPointFolder, "test-not-matching-control")
- );
- await act({ variantPaths, configFiles: new Map() });
+ pointCut.joinPointResolver.mockReturnValue(joinPointPath);
+ isJoinPointInvalid.mockReturnValue(true);
+ await act({
+ variantPaths,
+ configFiles: new Map()
+ });
+ });
+
+ makeCommonAssertions();
+
+ it("should call isJoinPointInvalid with the expected arguments", () => {
+ expect(isJoinPointInvalid).toHaveBeenCalledWith({
+ filename,
+ joinPointPath,
+ directory: joinPointFolder,
+ ...rest
+ });
});
it("should add no warnings, and not modify joinPointFiles", async () => {
@@ -79,41 +102,27 @@ describe("processVariantFiles", () => {
describe("when given a variant file that has a matching join point file", () => {
beforeEach(async () => {
- joinPointResolver.mockReturnValue(joinPointPath);
+ pointCut.joinPointResolver.mockReturnValue(joinPointPath);
});
describe("and no config file precludes it being valid", () => {
beforeEach(async () => {
- await act({ variantPaths, configFiles: new Map() });
+ isJoinPointInvalid.mockReturnValue(false);
+ await act({ variantPaths });
});
- it("should add no warnings, and add a single joinPointFile representing the matched join point", async () => {
- expect(warnings).toEqual([]);
- expect(joinPointFiles).toEqual(
- new Map([
- [
- joinPointPath,
- {
- pointCut,
- variants: [expectedVariant]
- }
- ]
- ])
- );
- });
- });
+ makeCommonAssertions();
- describe("and a config file confirms it as valid", () => {
- beforeEach(async () => {
- await act({
- variantPaths,
- configFiles: new Map([
- [joinPointFolder, { joinPoints: [moduleFile] }]
- ])
+ it("should call isJoinPointInvalid with the expected arguments", () => {
+ expect(isJoinPointInvalid).toHaveBeenCalledWith({
+ filename: moduleFile,
+ joinPointPath,
+ directory: joinPointFolder,
+ ...rest
});
});
- it("should add no warnings, and add a single joinPointFile representing the matched join point", async () => {
+ it("should add no warnings, and add a single joinPointFile representing the matched join point, relative to the control module", async () => {
expect(warnings).toEqual([]);
expect(joinPointFiles).toEqual(
new Map([
@@ -121,7 +130,7 @@ describe("processVariantFiles", () => {
joinPointPath,
{
pointCut,
- variants: [expectedVariant]
+ variantPathMap: new Map([[expectedVariant, path]])
}
]
])
@@ -129,20 +138,6 @@ describe("processVariantFiles", () => {
});
});
- describe("and a config file precludes it from being valid", () => {
- beforeEach(async () => {
- await act({
- variantPaths,
- configFiles: new Map([[joinPointFolder, { joinPoints: [] }]])
- });
- });
-
- it("should add no warnings, and not modify joinPointFiles", async () => {
- expect(warnings).toEqual([]);
- expect(joinPointFiles).toEqual(new Map());
- });
- });
-
describe("and a preceding point cut already identified the join point", () => {
const testOtherPointCut = { name: "test-other-point-cut" };
beforeEach(async () => {
@@ -150,11 +145,16 @@ describe("processVariantFiles", () => {
pointCut: testOtherPointCut
});
await act({
- variantPaths,
- configFiles: new Map()
+ variantPaths
});
});
+ makeCommonAssertions();
+
+ it("should not check if the join point is invalid again", () => {
+ expect(isJoinPointInvalid).not.toHaveBeenCalled();
+ });
+
it("should add a warning, and not modify joinPointFiles", async () => {
expect(warnings).toEqual([
`Join point "${joinPointPath}" is already assigned to point cut "${testOtherPointCut.name}". Skipping assignment to "${pointCut.name}".`
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.js
new file mode 100644
index 0000000..4b6dd65
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.js
@@ -0,0 +1,13 @@
+import { JOIN_POINTS, SCHEME } from "../../constants.js";
+
+const linkJoinPoints = (joinPointFiles) => {
+ for (const [, { variantPathMap }] of joinPointFiles) {
+ for (const [key, path] of variantPathMap) {
+ if (joinPointFiles.has(path)) {
+ variantPathMap.set(key, `${SCHEME}:${JOIN_POINTS}:${path}`);
+ }
+ }
+ }
+};
+
+export default linkJoinPoints;
diff --git a/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.test.js b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.test.js
new file mode 100644
index 0000000..ad8b4ff
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/processPointCuts/processVariantFiles/linkJoinPoints.test.js
@@ -0,0 +1,109 @@
+import linkJoinPoints from "./linkJoinPoints";
+import { JOIN_POINTS, SCHEME } from "../../constants.js";
+
+jest.mock("../../constants.js", () => ({
+ JOIN_POINTS: "mockedJoinPoints",
+ SCHEME: "mockedScheme"
+}));
+
+describe("linkJoinPoints", () => {
+ let mockJoinPoint1, mockJoinPoint2;
+ beforeEach(() => {
+ mockJoinPoint1 = [
+ "path/to/joinPoint1",
+ {
+ variantPathMap: new Map([
+ ["path/to/jointPoint1/variant1", "path/to/jointPoint1/variant1"],
+ ["path/to/jointPoint1/variant2", "path/to/jointPoint1/variant2"]
+ ])
+ }
+ ];
+ mockJoinPoint2 = [
+ "path/to/joinPoint2",
+ {
+ variantPathMap: new Map([
+ ["path/to/jointPoint2/variant1", "path/to/jointPoint2/variant1"],
+ ["path/to/jointPoint2/variant2", "path/to/jointPoint2/variant2"]
+ ])
+ }
+ ];
+ });
+
+ describe("when join points are not chained", () => {
+ it("should not modify the join point files", () => {
+ const joinPointFiles = new Map([mockJoinPoint1, mockJoinPoint2]);
+ linkJoinPoints(joinPointFiles);
+
+ expect(joinPointFiles).toEqual(
+ new Map([
+ [
+ "path/to/joinPoint1",
+ {
+ variantPathMap: new Map([
+ [
+ "path/to/jointPoint1/variant1",
+ "path/to/jointPoint1/variant1"
+ ],
+ ["path/to/jointPoint1/variant2", "path/to/jointPoint1/variant2"]
+ ])
+ }
+ ],
+ [
+ "path/to/joinPoint2",
+ {
+ variantPathMap: new Map([
+ [
+ "path/to/jointPoint2/variant1",
+ "path/to/jointPoint2/variant1"
+ ],
+ ["path/to/jointPoint2/variant2", "path/to/jointPoint2/variant2"]
+ ])
+ }
+ ]
+ ])
+ );
+ });
+ });
+
+ describe("when a variant of a join point is itself a join point", () => {
+ it("should link variants of the join point to the connected join point", () => {
+ const connectedJoinPoint2 = [
+ "path/to/jointPoint1/variant1",
+ mockJoinPoint2[1]
+ ];
+
+ const joinPointFiles = new Map([mockJoinPoint1, connectedJoinPoint2]);
+
+ linkJoinPoints(joinPointFiles);
+
+ expect(joinPointFiles).toEqual(
+ new Map([
+ [
+ "path/to/joinPoint1",
+ {
+ variantPathMap: new Map([
+ [
+ "path/to/jointPoint1/variant1",
+ `${SCHEME}:${JOIN_POINTS}:path/to/jointPoint1/variant1`
+ ],
+ ["path/to/jointPoint1/variant2", "path/to/jointPoint1/variant2"]
+ ])
+ }
+ ],
+ [
+ "path/to/jointPoint1/variant1",
+ {
+ variantPathMap: new Map([
+ [
+ "path/to/jointPoint2/variant1",
+ "path/to/jointPoint2/variant1"
+ ],
+ ["path/to/jointPoint2/variant2", "path/to/jointPoint2/variant2"]
+ ])
+ }
+ ]
+ ])
+ );
+ });
+ });
+});
diff --git a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.js b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.js
index 9f36121..40e24f2 100644
--- a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.js
+++ b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.js
@@ -1,5 +1,5 @@
import { PLUGIN_NAME } from "../constants";
-import { posix, win32 } from "path";
+import { sep, posix } from "path";
import { promisify } from "util";
import handleJoinPointMatch from "./handleJoinPointMatch";
const { relative } = posix;
@@ -7,6 +7,33 @@ const { relative } = posix;
const isLoaderlessFileRequest = (request) =>
[".", "/"].includes(request.at(0)) && !request.includes("!");
+const matchJoinPointIfResolved = async ({
+ enhancedResolve,
+ resolveData,
+ appRoot,
+ joinPointFiles,
+ compilation
+}) => {
+ const resolved = await enhancedResolve(
+ {},
+ resolveData.context,
+ resolveData.request,
+ {}
+ );
+ if (!resolved) {
+ return;
+ }
+
+ const resource = `/${relative(appRoot, resolved.replaceAll(sep, posix.sep))}`;
+ if (joinPointFiles.has(resource)) {
+ handleJoinPointMatch({
+ resource,
+ compilation,
+ resolveData
+ });
+ }
+};
+
const resolveJoinPoints = ({
compilation,
appRoot,
@@ -23,29 +50,19 @@ const resolveJoinPoints = ({
async (resolveData) => {
if (
!joinPointFiles.size ||
- !resolveData.context
- .replaceAll(win32.sep, posix.sep)
- .startsWith(appRoot) ||
+ !resolveData.context.replaceAll(sep, posix.sep).startsWith(appRoot) ||
!isLoaderlessFileRequest(resolveData.request)
) {
return;
}
- const resolved = await enhancedResolve(
- {},
- resolveData.context,
- resolveData.request,
- {}
- );
-
- const resource = `/${relative(appRoot, resolved.replaceAll(win32.sep, posix.sep))}`;
- if (joinPointFiles.has(resource)) {
- handleJoinPointMatch({
- resource,
- compilation,
- resolveData
- });
- }
+ await matchJoinPointIfResolved({
+ appRoot,
+ joinPointFiles,
+ enhancedResolve,
+ resolveData,
+ compilation
+ });
}
);
};
diff --git a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.test.js b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.test.js
index e9628c8..b08d897 100644
--- a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/index.test.js
@@ -1,7 +1,7 @@
import { PLUGIN_NAME } from "../constants";
import handleJoinPointMatch from "./handleJoinPointMatch";
import { sep, join } from "path";
-import resolvePointCuts from ".";
+import resolveJoinPoints from ".";
jest.mock("../constants", () => ({
PLUGIN_NAME: "test-plugin-name"
@@ -48,7 +48,7 @@ describe("resolveJoinPoints", () => {
const joinPointFiles = new Map();
beforeEach(() => {
- resolvePointCuts({
+ resolveJoinPoints({
compilation,
appRoot,
normalModuleFactory,
@@ -64,7 +64,7 @@ describe("resolveJoinPoints", () => {
beforeEach(() => {
[, beforeResolveCallback] =
normalModuleFactory.hooks.beforeResolve.tapPromise.mock.lastCall;
- handleJoinPointMatch.mockClear();
+ jest.clearAllMocks();
beforeResolveCallback();
});
@@ -77,7 +77,7 @@ describe("resolveJoinPoints", () => {
describe("when there are some join points previously identified", () => {
const joinPointFile = "/test-folder/test-join-point-file";
beforeEach(() => {
- resolvePointCuts({
+ resolveJoinPoints({
compilation,
appRoot,
normalModuleFactory,
@@ -157,6 +157,19 @@ describe("resolveJoinPoints", () => {
});
};
+ describe("and the file cannot be resolved", () => {
+ beforeEach(() => {
+ mockResolvedResource = false;
+ beforeResolveCallback(resolveData);
+ });
+
+ makeCommonAssertions();
+
+ it("should not try to handle a match", () => {
+ expect(handleJoinPointMatch).not.toHaveBeenCalled();
+ });
+ });
+
describe("and the file is not a join point", () => {
beforeEach(() => {
mockResolvedResource = join(appRoot, "some-other-file");
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.js
deleted file mode 100644
index cab2b71..0000000
--- a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import { posix } from "path";
-import regexgen from "regexgen";
-import { POINT_CUTS, SCHEME } from "../constants.js";
-const { dirname } = posix;
-
-const generateJoinPoint = ({ joinPointFiles, path }) => {
- const {
- pointCut: { name },
- variants
- } = joinPointFiles.get(path);
- const directory = dirname(path);
- const regex = regexgen(variants);
-
- return `import pointCut from "${SCHEME}:${POINT_CUTS}:/${name}";
-import * as joinPoint from "${path}";
-const variants = import.meta.webpackContext("${directory}", { recursive: true, regExp: ${regex} });
-export default pointCut({ joinPoint, variants });`;
-};
-
-export default generateJoinPoint;
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.test.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.test.js
deleted file mode 100644
index d03a273..0000000
--- a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint.test.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { POINT_CUTS, SCHEME } from "../constants.js";
-import generateJoinPoint from "./generateJoinPoint.js";
-
-jest.mock("../constants", () => ({
- SCHEME: "test-scheme",
- POINT_CUTS: "test-point-cuts"
-}));
-
-describe("generateJoinPoint", () => {
- const path = "test-folder/test-path";
- const pointCutName = "test-point-cut";
- const variants = [
- "test-sub-folder/test-variant-1",
- "test-sub-folder/test-variant-2",
- "test-other-sub-folder/test-variant-1"
- ];
- let result;
-
- beforeEach(() => {
- const joinPointFiles = new Map([
- [path, { pointCut: { name: pointCutName }, variants }]
- ]);
- result = generateJoinPoint({ joinPointFiles, path });
- });
-
- it("should return a script that imports the appropriate point cut for the join point", () => {
- expect(result).toMatch(
- `import pointCut from "${SCHEME}:${POINT_CUTS}:/${pointCutName}";`
- );
- });
-
- it("should return a script that imports the base / control module for the join point", () => {
- expect(result).toMatch(`import * as joinPoint from "${path}";`);
- });
-
- it("should return a script that imports all the valid variants of the base / control module into a webpackContext, using a minimal regex that matches all the variants", () => {
- expect(result).toMatch(
- `const variants = import.meta.webpackContext("${
- path.split("/")[0]
- }", { recursive: true, regExp: /test\\-(?:other\\-sub\\-folder\\/test\\-variant\\-1|sub\\-folder\\/test\\-variant\\-[12])/ });`
- );
- });
-
- it("should return a script exports a default export which calls the point cut, passing the join point (control module) and the variants", () => {
- expect(result).toMatch("export default pointCut({ joinPoint, variants });");
- });
-});
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.js
new file mode 100644
index 0000000..770367f
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.js
@@ -0,0 +1,5 @@
+const createVariantPathMap = (content) => `const variantPathMap = new Map([
+${content}
+]);`;
+
+export default createVariantPathMap;
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.test.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.test.js
new file mode 100644
index 0000000..cabf55a
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/createVariantPathMap.test.js
@@ -0,0 +1,11 @@
+import createVariantPathMap from "./createVariantPathMap";
+
+describe("createVariantPathMap", () => {
+ it("should return code to create a variantPathMap constant, wrapping the supplied content in a Map", () => {
+ const testContent = "test-content";
+ expect(createVariantPathMap(testContent))
+ .toEqual(`const variantPathMap = new Map([
+${testContent}
+]);`);
+ });
+});
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.js
new file mode 100644
index 0000000..49a6583
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.js
@@ -0,0 +1,15 @@
+import createVariantPathMap from "./createVariantPathMap.js";
+
+const importCodeGenerator = ({ joinPointPath, variantPathMap }) => {
+ const variantsKeys = Array.from(variantPathMap.keys());
+ return `import * as joinPoint from "${joinPointPath}";
+${variantsKeys
+ .map(
+ (key, index) =>
+ `import * as variant_${index} from "${variantPathMap.get(key)}";`
+ )
+ .join("\n")}
+${createVariantPathMap(variantsKeys.map((key, index) => ` ["${key}", variant_${index}]`).join(",\n"))}`;
+};
+
+export default importCodeGenerator;
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.test.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.test.js
new file mode 100644
index 0000000..f80d411
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/importCodeGenerator.test.js
@@ -0,0 +1,44 @@
+import importCodeGenerator from "./importCodeGenerator";
+
+describe("importCodeGenerator", () => {
+ const joinPointPath = "/test-folder/test-path";
+ const relativePaths = [
+ "/test-sub-folder/test-variant-1",
+ "/test-sub-folder/test-variant-2",
+ "/test-other-sub-folder/test-variant-1"
+ ];
+ const variantPathMap = new Map(
+ relativePaths.map((relativePath) => [
+ relativePath,
+ `${joinPointPath}${relativePath}`
+ ])
+ );
+
+ let result;
+
+ beforeEach(() => {
+ result = importCodeGenerator({
+ joinPointPath,
+ variantPathMap
+ });
+ });
+
+ it("should return code that imports the base / control module for the join point", () => {
+ expect(result).toMatch(`import * as joinPoint from "${joinPointPath}";`);
+ });
+
+ it("should return code that imports all the valid variants of the base / control module, storing in variables", () => {
+ expect(result).toMatch(`
+import * as variant_0 from "${joinPointPath}${relativePaths[0]}";
+import * as variant_1 from "${joinPointPath}${relativePaths[1]}";
+import * as variant_2 from "${joinPointPath}${relativePaths[2]}";`);
+ });
+
+ it("should return code that creates a Map of variants, keyed by relative path, valued as the variant module", () => {
+ expect(result).toMatch(`const variantPathMap = new Map([
+ ["/test-sub-folder/test-variant-1", variant_0],
+ ["/test-sub-folder/test-variant-2", variant_1],
+ ["/test-other-sub-folder/test-variant-1", variant_2]
+]);`);
+ });
+});
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.js
new file mode 100644
index 0000000..58b7ea6
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.js
@@ -0,0 +1,18 @@
+import { POINT_CUTS, SCHEME } from "../../constants.js";
+import importCodeGenerator from "./importCodeGenerator.js";
+
+const generateJoinPoint = ({ joinPointFiles, joinPointPath }) => {
+ const {
+ pointCut: { name },
+ variantPathMap
+ } = joinPointFiles.get(joinPointPath);
+ const pointCutImport = `import pointCut from "${SCHEME}:${POINT_CUTS}:/${name}";`;
+
+ const code = importCodeGenerator({ joinPointPath, variantPathMap });
+
+ return `${pointCutImport}
+${code}
+export default pointCut({ joinPoint, variantPathMap });`;
+};
+
+export default generateJoinPoint;
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.test.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.test.js
new file mode 100644
index 0000000..3a114d8
--- /dev/null
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generateJoinPoint/index.test.js
@@ -0,0 +1,51 @@
+import { POINT_CUTS, SCHEME } from "../../constants.js";
+import generateJoinPoint from "./index.js";
+import importCodeGenerator from "./importCodeGenerator.js";
+
+jest.mock("../../constants", () => ({
+ SCHEME: "test-scheme",
+ POINT_CUTS: "test-point-cuts"
+}));
+const mockImportCode =
+ "const joinPoint = 'test-join-point'; const variantPathMap = 'test-variants';";
+jest.mock("./importCodeGenerator.js", () => jest.fn(() => mockImportCode));
+
+describe("generateJoinPoint", () => {
+ const joinPointPath = "/test-path";
+ const pointCutName = "test-point-cut";
+ const variantPathMap = Symbol("test-variant-path-map");
+ const pointCut = {
+ name: pointCutName
+ };
+ let result;
+
+ beforeEach(() => {
+ const joinPointFiles = new Map([
+ [joinPointPath, { pointCut, variantPathMap }]
+ ]);
+ result = generateJoinPoint({
+ joinPointFiles,
+ joinPointPath
+ });
+ });
+
+ it("should return a script that imports the appropriate point cut for the join point", () => {
+ expect(result).toMatch(
+ `import pointCut from "${SCHEME}:${POINT_CUTS}:/${pointCutName}";`
+ );
+ });
+
+ it("should call the import code generator of the passed loading strategy, and return a script that includes the import code", () => {
+ expect(importCodeGenerator).toHaveBeenCalledWith({
+ joinPointPath,
+ variantPathMap
+ });
+ expect(result).toMatch(mockImportCode);
+ });
+
+ it("should return a script that exports a default export which calls the point cut, passing the join point (control module) and the variantPathMap returned by the import code", () => {
+ expect(result).toMatch(
+ "export default pointCut({ joinPoint, variantPathMap });"
+ );
+ });
+});
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.js
index bb104dc..4361c83 100644
--- a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.js
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.js
@@ -1,5 +1,5 @@
-const generatePointCut = ({ pointCuts, path }) => {
- const pointCutName = path.slice(1);
+const generatePointCut = ({ pointCuts, joinPointPath }) => {
+ const pointCutName = joinPointPath.slice(1);
const {
togglePointModule,
toggleHandler = "@asos/web-toggle-point-webpack/pathSegmentToggleHandler"
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.test.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.test.js
index cbcc7d6..f825a7c 100644
--- a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/generatePointCut.test.js
@@ -2,7 +2,7 @@ import generatePointCut from "./generatePointCut.js";
describe("generatePointCut", () => {
const pointCutName = "test-point-cut";
- const path = `/${pointCutName}`;
+ const joinPointPath = `/${pointCutName}`;
const togglePointModule = "test-toggle-point-path";
let result, pointCuts;
@@ -30,7 +30,7 @@ describe("generatePointCut", () => {
beforeEach(() => {
pointCuts[1].toggleHandler = toggleHandler;
- result = generatePointCut({ pointCuts, path });
+ result = generatePointCut({ pointCuts, joinPointPath });
});
it("should return a script that imports the appropriate toggle handler", () => {
@@ -42,7 +42,7 @@ describe("generatePointCut", () => {
describe("when a toggle handler is not configured against the point cut", () => {
beforeEach(() => {
- result = generatePointCut({ pointCuts, path });
+ result = generatePointCut({ pointCuts, joinPointPath });
});
it("should return a script that imports the default toggle handler (a path segment toggle handler)", () => {
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.js
index b5d014f..db42a9c 100644
--- a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.js
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.js
@@ -1,5 +1,5 @@
import { PLUGIN_NAME, POINT_CUTS, JOIN_POINTS, SCHEME } from "../constants.js";
-import generateJoinPoint from "./generateJoinPoint.js";
+import generateJoinPoint from "./generateJoinPoint/index.js";
import generatePointCut from "./generatePointCut.js";
const setupSchemeModules = ({
@@ -11,13 +11,13 @@ const setupSchemeModules = ({
NormalModule.getCompilationHooks(compilation)
.readResource.for(SCHEME)
.tap(PLUGIN_NAME, ({ resourcePath }) => {
- const [, type, path] = resourcePath.split(/:(.*?):(.*)/, 3);
+ const [, type, joinPointPath] = resourcePath.split(/:(.*?):(.*)/, 3);
switch (type) {
case POINT_CUTS: {
- return generatePointCut({ pointCuts, path });
+ return generatePointCut({ pointCuts, joinPointPath });
}
case JOIN_POINTS: {
- return generateJoinPoint({ joinPointFiles, path });
+ return generateJoinPoint({ joinPointFiles, joinPointPath });
}
}
});
diff --git a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.test.js b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.test.js
index ca8a234..da55147 100644
--- a/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/setupSchemeModules/index.test.js
@@ -1,5 +1,5 @@
import { PLUGIN_NAME, POINT_CUTS, JOIN_POINTS, SCHEME } from "../constants.js";
-import generateJoinPoint from "./generateJoinPoint.js";
+import generateJoinPoint from "./generateJoinPoint/index.js";
import generatePointCut from "./generatePointCut.js";
import setupSchemeModules from "./index.js";
@@ -46,35 +46,42 @@ describe("setupSchemeModules", () => {
let result;
describe("and the resource is prefixed with the point cuts type", () => {
- const path = "test-point-cut-name";
+ const joinPointPath = "test-point-cut-name";
const output = Symbol("test-output");
beforeEach(() => {
const [, callback] = tap.mock.lastCall;
generatePointCut.mockReturnValue(output);
- result = callback({ resourcePath: `${SCHEME}:${POINT_CUTS}:${path}` });
+ result = callback({
+ resourcePath: `${SCHEME}:${POINT_CUTS}:${joinPointPath}`
+ });
});
it("should generate the point cut and return the generated module to the read resource hook", () => {
- expect(generatePointCut).toHaveBeenCalledWith({ pointCuts, path });
+ expect(generatePointCut).toHaveBeenCalledWith({
+ pointCuts,
+ joinPointPath
+ });
expect(result).toBe(output);
});
});
describe("and the resource is prefixed with the join points type", () => {
- const path = "test-path";
+ const joinPointPath = "test-path";
const output = Symbol("test-output");
beforeEach(() => {
const [, callback] = tap.mock.lastCall;
generateJoinPoint.mockReturnValue(output);
- result = callback({ resourcePath: `${SCHEME}:${JOIN_POINTS}:${path}` });
+ result = callback({
+ resourcePath: `${SCHEME}:${JOIN_POINTS}:${joinPointPath}`
+ });
});
it("should generate a join point and return the generated module to the read resource hook", () => {
expect(generateJoinPoint).toHaveBeenCalledWith({
joinPointFiles,
- path
+ joinPointPath
});
expect(result).toBe(output);
});
diff --git a/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.js b/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.js
index 99a2633..5c568d3 100644
--- a/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.js
+++ b/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.js
@@ -1,9 +1,9 @@
-const buildTree = (map = new Map(), parts, variants, key) => {
+const buildTree = (map = new Map(), parts, value) => {
const [part, ...rest] = parts;
if (rest.length) {
- map.set(part, buildTree(map.get(part), rest, variants, key));
+ map.set(part, buildTree(map.get(part), rest, value));
} else {
- map.set(part, variants(key));
+ map.set(part, value);
}
return map;
};
@@ -15,14 +15,18 @@ const buildTree = (map = new Map(), parts, variants, key) => {
* @param {object} options plugin options
* @param {function} options.togglePoint a method that chooses the appropriate module at runtime
* @param {module} options.joinPoint the join point module
- * @param {string[]} options.variants an array of paths, as generated by webpack, that point to variants of the join point module
+ * @param {Map} params.variantPathMap a Map of posix file paths, relative to the join point module, to variant modules
* @returns {function} A handler of join points injected by the plugin
*/
-const pathSegmentToggleHandler = ({ togglePoint, joinPoint, variants }) => {
+const pathSegmentToggleHandler = ({
+ togglePoint,
+ joinPoint,
+ variantPathMap
+}) => {
let featuresMap;
- for (const key of variants.keys()) {
+ for (const [key, value] of variantPathMap) {
const parts = key.split("/").slice(0, -1).slice(2);
- featuresMap = buildTree(featuresMap, parts, variants, key);
+ featuresMap = buildTree(featuresMap, parts, value);
}
return togglePoint(joinPoint, featuresMap);
};
diff --git a/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js b/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js
index 6e64730..722624e 100644
--- a/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js
+++ b/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js
@@ -5,9 +5,7 @@ const togglePoint = jest.fn(() => toggleOutcome);
const joinPoint = Symbol("mock-join-point");
describe("pathSegmentToggleHandler", () => {
- let result, variantsMap;
- const variants = (key) => variantsMap[key];
- variants.keys = () => Object.keys(variantsMap);
+ let result;
beforeEach(() => {
jest.clearAllMocks();
@@ -17,15 +15,25 @@ describe("pathSegmentToggleHandler", () => {
const keyArray = [...Array(segmentCount).keys()];
describe(`given a list of variant paths with ${segmentCount} path segments (after the variants path)`, () => {
+ let variantPathMap;
+
beforeEach(() => {
const segments = keyArray.map((key) => `test-segment-${key}/`);
- variantsMap = {
- [`./__variants__/${segments.join("")}test-variant.js`]:
- Symbol("test-variant"),
- [`./__variants__/${segments.reverse().join("")}test-variant.js`]:
+ variantPathMap = new Map([
+ [
+ `./__variants__/${segments.join("")}test-variant.js`,
+ Symbol("test-variant")
+ ],
+ [
+ `./__variants__/${segments.reverse().join("")}test-variant.js`,
Symbol("test-variant")
- };
- result = pathSegmentToggleHandler({ togglePoint, joinPoint, variants });
+ ]
+ ]);
+ result = pathSegmentToggleHandler({
+ togglePoint,
+ joinPoint,
+ variantPathMap
+ });
});
it("should call the toggle point with the join point module and a map", () => {
@@ -44,14 +52,14 @@ describe("pathSegmentToggleHandler", () => {
});
it("should return a map containing maps for each segment, concluding with the variant at the leaf node", () => {
- for (const key of Object.keys(variantsMap)) {
+ for (const key of Object.keys(variantPathMap)) {
const segments = key.split("/").slice(0, -1);
let node = map;
for (const segment of segments.slice(2)) {
expect(node.has(segment)).toBe(true);
node = node.get(segment);
}
- expect(node).toBe(variantsMap[key]);
+ expect(node).toBe(variantPathMap[key]);
}
});
});
diff --git a/packages/webpack/test/test-utils.js b/packages/webpack/test/test-utils.js
index 7065956..726c018 100644
--- a/packages/webpack/test/test-utils.js
+++ b/packages/webpack/test/test-utils.js
@@ -20,7 +20,6 @@ export const createMockGraph = ({ depth, siblingsAtEachDepthCount }) => {
createGraph(rootNode, depth, siblingsAtEachDepthCount);
const getIncomingConnections = jest.fn(function* (module) {
- // eslint-disable-next-line jsdoc/require-jsdoc
function* traverse(node) {
if (node.resource === module.resource) {
yield* issuersMap.get(node).map((node) => ({
From e41ef947bb543ff7cc0e29ea5dbd7512b4ac9b8b Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 29 Jul 2025 21:25:35 +0100
Subject: [PATCH 06/44] use get()
---
.../webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js b/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js
index 722624e..ecf556f 100644
--- a/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js
+++ b/packages/webpack/src/toggleHandlers/pathSegmentToggleHandler.test.js
@@ -59,7 +59,7 @@ describe("pathSegmentToggleHandler", () => {
expect(node.has(segment)).toBe(true);
node = node.get(segment);
}
- expect(node).toBe(variantPathMap[key]);
+ expect(node).toBe(variantPathMap.get(key));
}
});
});
From a30583bdade0eadf1df272b46a48a9f2b38e047d Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Mon, 4 Aug 2025 16:06:43 +0100
Subject: [PATCH 07/44] fix version link in CHANGELOGs to use correct date
---
examples/next/docs/CHANGELOG.md | 2 +-
examples/serve/docs/CHANGELOG.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/next/docs/CHANGELOG.md b/examples/next/docs/CHANGELOG.md
index e918e3c..dfd5a58 100644
--- a/examples/next/docs/CHANGELOG.md
+++ b/examples/next/docs/CHANGELOG.md
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- update to take supply static `webpackNormalModule` corresponding to webpack plugin [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-05-29)
+- update to take supply static `webpackNormalModule` corresponding to webpack plugin [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-07-29)
## [0.2.4] - 2025-05-27
diff --git a/examples/serve/docs/CHANGELOG.md b/examples/serve/docs/CHANGELOG.md
index e2ca06f..17cf9f2 100644
--- a/examples/serve/docs/CHANGELOG.md
+++ b/examples/serve/docs/CHANGELOG.md
@@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-- updated toggle handlers to take a `variantPathMap` corresponding to webpack [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-05-29)
+- updated toggle handlers to take a `variantPathMap` corresponding to webpack [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-07-29)
## [0.2.6] - 2025-07-14
From 42a078456c7d6cef435761db3a6a85100415e753 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Mon, 4 Aug 2025 16:10:10 +0100
Subject: [PATCH 08/44] more CHANGELOG date fix
---
examples/next/docs/CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/examples/next/docs/CHANGELOG.md b/examples/next/docs/CHANGELOG.md
index dfd5a58..08af4aa 100644
--- a/examples/next/docs/CHANGELOG.md
+++ b/examples/next/docs/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [0.2.5] - 2025-05-29
+## [0.2.5] - 2025-07-29
### Changed
From 904e2e53ee862f916554fbca5976c9d3395d18cc Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 19 Aug 2025 10:15:47 +0100
Subject: [PATCH 09/44] handle circular references
---
packages/webpack/docs/CHANGELOG.md | 1 +
.../resourceProxyExistsInRequestChain.js | 6 ++
.../resourceProxyExistsInRequestChain.test.js | 63 +++++++++++++------
3 files changed, 52 insertions(+), 18 deletions(-)
diff --git a/packages/webpack/docs/CHANGELOG.md b/packages/webpack/docs/CHANGELOG.md
index 66419da..18853e4 100644
--- a/packages/webpack/docs/CHANGELOG.md
+++ b/packages/webpack/docs/CHANGELOG.md
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- removed "next" peer dependency, this needn't be explicit
- ensured files that cannot be resolved (by [enhanced-resolve](https://github.com/webpack/enhanced-resolve/)), for whatever reason, don't break the build
+- ensured that circular dependencies don't cause the module graph search lock up
## [0.8.0] - 2025-05-27
diff --git a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.js b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.js
index 83e8d3b..bfc049c 100644
--- a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.js
+++ b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.js
@@ -4,12 +4,18 @@ const resourceProxyExistsInRequestChain = ({
proxyResource
}) => {
const queue = [issuerModule];
+ const visited = new Set();
while (queue.length) {
const node = queue.shift();
if (node.resource === proxyResource) {
return true;
}
+ if (visited.has(node)) {
+ continue;
+ }
+ visited.add(node);
+
const incomingConnections = moduleGraph.getIncomingConnections(node);
queue.push(
...new Set(
diff --git a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.test.js b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.test.js
index 058a137..de74b7a 100644
--- a/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.test.js
+++ b/packages/webpack/src/plugins/togglePointInjection/resolveJoinPoints/handleJoinPointMatch/resourceProxyExistsInRequestChain.test.js
@@ -1,13 +1,14 @@
import resourceProxyExistsInRequestChain from "./resourceProxyExistsInRequestChain";
import { createMockGraph } from "../../../../../test/test-utils";
-const moduleGraph = { getIncomingConnections: jest.fn() };
const proxyResource = Symbol("test-proxy-resource");
describe("resourceProxyExistsInRequestChain", () => {
let result;
describe("when the issuer module is the proxy resource", () => {
+ const moduleGraph = { getIncomingConnections: jest.fn() };
+
beforeEach(() => {
result = resourceProxyExistsInRequestChain({
moduleGraph,
@@ -118,28 +119,54 @@ describe("resourceProxyExistsInRequestChain", () => {
});
describe("and one of the modules that imported the issuer module was not imported by the proxy resource", () => {
- let calls;
-
- beforeEach(() => {
- result = resourceProxyExistsInRequestChain({
- moduleGraph,
- issuerModule,
- proxyResource
+ describe("and there is a circular dependency", () => {
+ beforeEach(() => {
+ let count = 0;
+ const newModuleGraph = {
+ ...moduleGraph,
+ getIncomingConnections: jest.fn().mockImplementation((module) => {
+ if (count++ === 10) {
+ count = 0;
+ return moduleGraph.getIncomingConnections(issuerModule);
+ }
+ return moduleGraph.getIncomingConnections(module);
+ })
+ };
+ result = resourceProxyExistsInRequestChain({
+ moduleGraph: newModuleGraph,
+ issuerModule,
+ proxyResource
+ });
});
- calls = moduleGraph.getIncomingConnections.mock.calls;
+ it("should return false, without locking up / running forever", () => {
+ expect(result).toBe(false);
+ });
});
- it("should have traversed the whole import tree of the issuer module", () => {
- let expectedCount = 1;
- for (let level = 1; level <= depth; level++) {
- expectedCount += Math.pow(siblingsAtEachDepthCount, level);
- }
- expect(calls.length).toEqual(expectedCount);
- });
+ describe("and there is no circular dependency", () => {
+ beforeEach(() => {
+ result = resourceProxyExistsInRequestChain({
+ moduleGraph,
+ issuerModule,
+ proxyResource
+ });
+ });
+
+ it("should have traversed the whole import tree of the issuer module", () => {
+ let expectedCount = 1;
+ for (let level = 1; level <= depth; level++) {
+ expectedCount += Math.pow(siblingsAtEachDepthCount, level);
+ }
- it("should return false", () => {
- expect(result).toBe(false);
+ expect(
+ moduleGraph.getIncomingConnections.mock.calls.length
+ ).toEqual(expectedCount);
+ });
+
+ it("should return false", () => {
+ expect(result).toBe(false);
+ });
});
});
});
From d199c1cb2f3114d866855c7b8b1e0741bf9f8841 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 19 Aug 2025 11:29:36 +0100
Subject: [PATCH 10/44] try being explicit about type import?
---
test/automation/base.config.ts | 2 +-
test/automation/docs/CHANGELOG.md | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/test/automation/base.config.ts b/test/automation/base.config.ts
index 3fa6253..d5f9920 100644
--- a/test/automation/base.config.ts
+++ b/test/automation/base.config.ts
@@ -1,4 +1,4 @@
-import { devices, ReporterDescription } from "@playwright/test";
+import { devices, type ReporterDescription } from "@playwright/test";
const baseConfig = {
fullyParallel: true,
diff --git a/test/automation/docs/CHANGELOG.md b/test/automation/docs/CHANGELOG.md
index 6a53fe4..2d6f487 100644
--- a/test/automation/docs/CHANGELOG.md
+++ b/test/automation/docs/CHANGELOG.md
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.1.3] - 2025-08-19
+
+- move to import type for `ReporterDescription`
+
## [0.1.2] - 2024-12-18
### Fixed
From bad0091a4ad8967a59a13430cf529e6dbd51b0f0 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 19 Aug 2025 11:49:19 +0100
Subject: [PATCH 11/44] import playwright types explicitly
---
examples/express/docs/CHANGELOG.md | 1 +
examples/express/playwright.config.ts | 2 +-
examples/next/docs/CHANGELOG.md | 4 ++++
examples/next/playwright.config.ts | 2 +-
examples/serve/docs/CHANGELOG.md | 4 ++++
examples/serve/playwright.config.ts | 2 +-
6 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/examples/express/docs/CHANGELOG.md b/examples/express/docs/CHANGELOG.md
index 03a6019..cfcccb5 100644
--- a/examples/express/docs/CHANGELOG.md
+++ b/examples/express/docs/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- removed "Vary" header from "animals" example, the page is meant to be un-cacheable, and the value was wrong in any case
+- import types explicitly from `@playwright/test` after unexpected pipeline failure
## [0.2.5] - 2025-05-27
diff --git a/examples/express/playwright.config.ts b/examples/express/playwright.config.ts
index 0288d5e..c0e2fbd 100644
--- a/examples/express/playwright.config.ts
+++ b/examples/express/playwright.config.ts
@@ -1,4 +1,4 @@
-import { defineConfig, PlaywrightTestConfig } from "@playwright/test";
+import { defineConfig, type PlaywrightTestConfig } from "@playwright/test";
import baseConfig from "../../test/automation/base.config";
const config: PlaywrightTestConfig = {
diff --git a/examples/next/docs/CHANGELOG.md b/examples/next/docs/CHANGELOG.md
index 08af4aa..84cc6eb 100644
--- a/examples/next/docs/CHANGELOG.md
+++ b/examples/next/docs/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- update to take supply static `webpackNormalModule` corresponding to webpack plugin [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-07-29)
+### Fixed
+
+- import types explicitly from `@playwright/test` after unexpected pipeline failure
+
## [0.2.4] - 2025-05-27
### Changed
diff --git a/examples/next/playwright.config.ts b/examples/next/playwright.config.ts
index 2f163c0..88d6b5e 100644
--- a/examples/next/playwright.config.ts
+++ b/examples/next/playwright.config.ts
@@ -1,4 +1,4 @@
-import { defineConfig, PlaywrightTestConfig } from "@playwright/test";
+import { defineConfig, type PlaywrightTestConfig } from "@playwright/test";
import baseConfig from "../../test/automation/base.config";
const THREE_MINUTES = 3 * 60 * 1000;
diff --git a/examples/serve/docs/CHANGELOG.md b/examples/serve/docs/CHANGELOG.md
index 17cf9f2..62bba3b 100644
--- a/examples/serve/docs/CHANGELOG.md
+++ b/examples/serve/docs/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- updated toggle handlers to take a `variantPathMap` corresponding to webpack [version 0.9.0](../../../packages/webpack/docs/CHANGELOG.md#090---2025-07-29)
+### Fixed
+
+- import types explicitly from `@playwright/test` after unexpected pipeline failure
+
## [0.2.6] - 2025-07-14
### Changed
diff --git a/examples/serve/playwright.config.ts b/examples/serve/playwright.config.ts
index c0a196a..1b73718 100644
--- a/examples/serve/playwright.config.ts
+++ b/examples/serve/playwright.config.ts
@@ -1,4 +1,4 @@
-import { defineConfig, PlaywrightTestConfig } from "@playwright/test";
+import { defineConfig, type PlaywrightTestConfig } from "@playwright/test";
import baseConfig from "../../test/automation/base.config";
const config: PlaywrightTestConfig = {
From 334d8f937de786b78a5a5c7e42a95e9f5316dfd1 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 19 Aug 2025 11:56:16 +0100
Subject: [PATCH 12/44] more type explicitness
---
examples/next/docs/CHANGELOG.md | 2 +-
.../app/fixtures/experiments/playwright.setExperimentHeaders.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/next/docs/CHANGELOG.md b/examples/next/docs/CHANGELOG.md
index 84cc6eb..be1aa72 100644
--- a/examples/next/docs/CHANGELOG.md
+++ b/examples/next/docs/CHANGELOG.md
@@ -13,7 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
-- import types explicitly from `@playwright/test` after unexpected pipeline failure
+- import types explicitly from `@playwright/test` & internally, after unexpected pipeline failure
## [0.2.4] - 2025-05-27
diff --git a/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts b/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts
index 20e0c84..1111f8f 100644
--- a/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts
+++ b/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts
@@ -6,7 +6,7 @@ import {
PlaywrightWorkerOptions
} from "@playwright/test";
-import { Experiments, Decision } from "./experiments";
+import type { Experiments, Decision } from "./experiments";
const setExperimentHeaders = (
test: TestType<
From 4eba157183d13e8582c178ec31995f7c57db41ad Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 19 Aug 2025 12:10:36 +0100
Subject: [PATCH 13/44] more explicit type imports
---
examples/next/src/app/fixtures/experiments/getExperiments.ts | 2 +-
examples/next/src/app/fixtures/experiments/layout.tsx | 2 +-
.../src/app/fixtures/experiments/playwright.locateInExample.ts | 2 +-
.../app/fixtures/experiments/playwright.setExperimentHeaders.ts | 2 +-
examples/next/src/app/layout.tsx | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/examples/next/src/app/fixtures/experiments/getExperiments.ts b/examples/next/src/app/fixtures/experiments/getExperiments.ts
index fc2f1ab..80450be 100644
--- a/examples/next/src/app/fixtures/experiments/getExperiments.ts
+++ b/examples/next/src/app/fixtures/experiments/getExperiments.ts
@@ -1,5 +1,5 @@
import { headers } from "next/headers";
-import { Experiments } from "./experiments";
+import type { Experiments } from "./experiments";
export default async function getExperiments(): Promise<
Experiments | Record
diff --git a/examples/next/src/app/fixtures/experiments/layout.tsx b/examples/next/src/app/fixtures/experiments/layout.tsx
index 7b23ca7..0fcf7c2 100644
--- a/examples/next/src/app/fixtures/experiments/layout.tsx
+++ b/examples/next/src/app/fixtures/experiments/layout.tsx
@@ -1,4 +1,4 @@
-import { ReactNode } from "react";
+import type { ReactNode } from "react";
import getExperiments from "./getExperiments";
import Example from "./example";
diff --git a/examples/next/src/app/fixtures/experiments/playwright.locateInExample.ts b/examples/next/src/app/fixtures/experiments/playwright.locateInExample.ts
index 32224e8..970c9d2 100644
--- a/examples/next/src/app/fixtures/experiments/playwright.locateInExample.ts
+++ b/examples/next/src/app/fixtures/experiments/playwright.locateInExample.ts
@@ -1,4 +1,4 @@
-import { Page, Locator } from "@playwright/test";
+import type { Page, Locator } from "@playwright/test";
function locateWithinExample(page: Page, testId: string): Locator {
return page.locator("#example").getByTestId(testId);
diff --git a/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts b/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts
index 1111f8f..4b16956 100644
--- a/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts
+++ b/examples/next/src/app/fixtures/experiments/playwright.setExperimentHeaders.ts
@@ -1,4 +1,4 @@
-import {
+import type {
TestType,
PlaywrightTestArgs,
PlaywrightTestOptions,
diff --git a/examples/next/src/app/layout.tsx b/examples/next/src/app/layout.tsx
index bcc6be7..0b642db 100644
--- a/examples/next/src/app/layout.tsx
+++ b/examples/next/src/app/layout.tsx
@@ -1,6 +1,6 @@
import { Didact_Gothic } from "next/font/google";
import styles from "./styles.module.css";
-import { ReactNode } from "react";
+import type { ReactNode } from "react";
const didactGothic = Didact_Gothic({
display: "swap",
From 7c71a5a96e5fdd37285fc8a6b0b3958ce1945292 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Tue, 19 Aug 2025 12:15:07 +0100
Subject: [PATCH 14/44] sigh... more types
---
.../fixtures/experiments/1-varied-component/playwright.spec.ts | 2 +-
.../fixtures/experiments/4-varied-variant/playwright.spec.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/examples/next/src/app/fixtures/experiments/1-varied-component/playwright.spec.ts b/examples/next/src/app/fixtures/experiments/1-varied-component/playwright.spec.ts
index 2350b62..e61d32d 100644
--- a/examples/next/src/app/fixtures/experiments/1-varied-component/playwright.spec.ts
+++ b/examples/next/src/app/fixtures/experiments/1-varied-component/playwright.spec.ts
@@ -1,4 +1,4 @@
-import { test, expect, ConsoleMessage } from "@playwright/test";
+import { test, expect, type ConsoleMessage } from "@playwright/test";
import setExperimentHeaders from "../playwright.setExperimentHeaders";
import locateWithinExample from "../playwright.locateInExample";
import getFixtureURL from "../playwright.getFixtureUrl";
diff --git a/examples/next/src/app/fixtures/experiments/4-varied-variant/playwright.spec.ts b/examples/next/src/app/fixtures/experiments/4-varied-variant/playwright.spec.ts
index 7e02386..e4b4fc4 100644
--- a/examples/next/src/app/fixtures/experiments/4-varied-variant/playwright.spec.ts
+++ b/examples/next/src/app/fixtures/experiments/4-varied-variant/playwright.spec.ts
@@ -1,4 +1,4 @@
-import { test, expect, ConsoleMessage } from "@playwright/test";
+import { test, expect, type ConsoleMessage } from "@playwright/test";
import setExperimentHeaders from "../playwright.setExperimentHeaders";
import locateWithinExample from "../playwright.locateInExample";
import getFixtureURL from "../playwright.getFixtureUrl";
From 955080fc5334a9b3e680de53559a65e96bc66d22 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Thu, 21 Aug 2025 18:42:50 +0100
Subject: [PATCH 15/44] version & changelog for test/automation
---
test/automation/docs/CHANGELOG.md | 2 ++
test/automation/package.json | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/test/automation/docs/CHANGELOG.md b/test/automation/docs/CHANGELOG.md
index 2d6f487..add0c91 100644
--- a/test/automation/docs/CHANGELOG.md
+++ b/test/automation/docs/CHANGELOG.md
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [0.1.3] - 2025-08-19
+## Changed
+
- move to import type for `ReporterDescription`
## [0.1.2] - 2024-12-18
diff --git a/test/automation/package.json b/test/automation/package.json
index 4798d47..70dd3cb 100644
--- a/test/automation/package.json
+++ b/test/automation/package.json
@@ -1,6 +1,6 @@
{
"name": "web-toggle-point-automation-tests",
- "version": "0.1.2",
+ "version": "0.1.3",
"main": "index.js",
"keywords": [],
"type": "module",
From b4b0f42b09f19dc4ec67277e6fd8a114038f0740 Mon Sep 17 00:00:00 2001
From: TomStrepsil <10725179+TomStrepsil@users.noreply.github.com>
Date: Thu, 21 Aug 2025 23:02:23 +0100
Subject: [PATCH 16/44] parallel folder example
---
examples/express/README.md | 10 +
examples/express/eslint.config.mjs | 30 +-
examples/express/package.json | 10 +-
examples/express/src/index.js | 3 +
.../src/routes/animals/featuresStore.js | 2 +-
.../express/src/routes/animals/middleware.js | 2 +-
.../express/src/routes/config/Component.jsx | 2 +-
.../div-style/Large/Component.jsx | 2 +-
.../div-style/Small/Component.jsx | 2 +-
.../src/routes/config/featuresStore.js | 2 +-
examples/express/src/routes/config/router.js | 2 +-
.../routes/parallel-folder-convention/App.tsx | 25 ++
.../parallel-folder-convention/README.md | 121 ++++++
.../feature1/components/BottomBox/index.tsx | 7 +
.../TopBoxChild/TopBoxButton/index.module.css | 4 +
.../feature1/components/TopBox/index.tsx | 11 +
.../__variants__/feature1/constants/index.ts | 1 +
.../components/TopBox/TopBoxChild/index.tsx | 17 +
.../TopBox/TopBoxChild/useFreeAnimals.ts | 15 +
.../__variants__/feature2/constants/index.ts | 1 +
.../feature2/state/modules/animals/slice.ts | 16 +
.../__variants__/feature3/constants/index.ts | 1 +
.../feature3/state/modules/animals/slice.ts | 21 +
.../__variants__/feature4/constants/index.ts | 1 +
.../feature4/state/modules/animals/slice.ts | 16 +
.../parallel-folder-convention/client.js | 4 +
.../AnimalPen/index.module.css | 11 +
.../component-library/AnimalPen/index.tsx | 9 +
.../component-library/control1.tsx | 18 +
.../component-library/control2.tsx | 18 +
.../component-library/styles.module.css | 29 ++
.../component-library/variant1.tsx | 18 +
.../component-library/variant2.tsx | 18 +
.../components/Animal/index.tsx | 5 +
.../components/BottomBox/index.tsx | 15 +
.../components/BottomBox/useAnimals.ts | 6 +
.../TopBoxChild/TopBoxButton/index.module.css | 6 +
.../TopBox/TopBoxChild/TopBoxButton/index.tsx | 12 +
.../TopBoxChild/TopBoxButton/useAddAnimal.ts | 11 +
.../components/TopBox/TopBoxChild/index.tsx | 11 +
.../components/TopBox/index.tsx | 11 +
.../constants/index.ts | 1 +
.../parallel-folder-convention/global.d.ts | 2 +
.../parallel-folder-convention/router.tsx | 56 +++
.../state/modules/animals/slice.ts | 24 +
.../state/modules/index.ts | 5 +
.../parallel-folder-convention/state/store.ts | 12 +
.../state/useAppDispatch.ts | 6 +
.../state/useAppSelector.ts | 6 +
.../parallel-folder-convention/styles.css | 54 +++
.../toggle-plumbing/constants.ts | 1 +
.../toggle-plumbing/featuresStore/browser.ts | 18 +
.../toggle-plumbing/featuresStore/index.ts | 9 +
.../toggle-plumbing/featuresStore/server.ts | 5 +
.../toggle-plumbing/pointCutConfig.js | 42 ++
.../toggle-plumbing/serialization.ts | 8 +
.../toggle-points/objectProxyTogglePoint.ts | 25 ++
.../reactComponentTogglePoint.ts | 9 +
.../toggle-points/reduxSliceTogglePoint.ts | 15 +
.../toggle-plumbing/toggleHandler.ts | 11 +
.../parallel-folder-convention/tsconfig.json | 26 ++
.../parallel-folder-convention/typings.d.ts | 1 +
examples/express/webpack.config.js | 60 ++-
package-lock.json | 411 +++++++++++++++---
64 files changed, 1273 insertions(+), 60 deletions(-)
create mode 100644 examples/express/src/routes/parallel-folder-convention/App.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/README.md
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature1/components/BottomBox/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature1/components/TopBox/TopBoxChild/TopBoxButton/index.module.css
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature1/components/TopBox/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature1/constants/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature2/components/TopBox/TopBoxChild/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature2/components/TopBox/TopBoxChild/useFreeAnimals.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature2/constants/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature2/state/modules/animals/slice.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature3/constants/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature3/state/modules/animals/slice.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature4/constants/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/__variants__/feature4/state/modules/animals/slice.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/client.js
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/AnimalPen/index.module.css
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/AnimalPen/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/control1.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/control2.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/styles.module.css
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/variant1.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/component-library/variant2.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/Animal/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/BottomBox/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/BottomBox/useAnimals.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/TopBox/TopBoxChild/TopBoxButton/index.module.css
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/TopBox/TopBoxChild/TopBoxButton/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/TopBox/TopBoxChild/TopBoxButton/useAddAnimal.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/TopBox/TopBoxChild/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/components/TopBox/index.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/constants/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/global.d.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/router.tsx
create mode 100644 examples/express/src/routes/parallel-folder-convention/state/modules/animals/slice.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/state/modules/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/state/store.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/state/useAppDispatch.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/state/useAppSelector.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/styles.css
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/constants.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/featuresStore/browser.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/featuresStore/index.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/featuresStore/server.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/pointCutConfig.js
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/serialization.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/toggle-points/objectProxyTogglePoint.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/toggle-points/reactComponentTogglePoint.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/toggle-points/reduxSliceTogglePoint.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/toggle-plumbing/toggleHandler.ts
create mode 100644 examples/express/src/routes/parallel-folder-convention/tsconfig.json
create mode 100644 examples/express/src/routes/parallel-folder-convention/typings.d.ts
diff --git a/examples/express/README.md b/examples/express/README.md
index ac9e6f6..311762e 100644
--- a/examples/express/README.md
+++ b/examples/express/README.md
@@ -9,3 +9,13 @@ Some example applications based on an [express](https://expressjs.com/) router
2. [config](./src/routes/config/README.md)
This example shows the use of the [`react-pointcuts`](../../packages/react-pointcuts/docs/README.md), [`features`](../../packages/features/docs/README.md), [`ssr`](../../packages/ssr/docs/README.md) and [`webpack`](../../packages/webpack/docs/README.md) packages.
+
+3. [parallel-folder-convention](./src/routes/config/README.md)
+
+ This example shows the use of the [`react-pointcuts`](../../packages/react-pointcuts/docs/README.md), [`features`](../../packages/features/docs/README.md), [`ssr`](../../packages/ssr/docs/README.md) and [`webpack`](../../packages/webpack/docs/README.md) packages.
+
+ It has a bespoke filesystem convention, with parallel directory hierarchies containing arbitrary replacements and patches of various types of module, including:
+ - constants
+ - css
+ - react components
+ - [redux slices](https://redux.js.org/tutorials/essentials/part-2-app-structure#redux-slices)
\ No newline at end of file
diff --git a/examples/express/eslint.config.mjs b/examples/express/eslint.config.mjs
index 27253ea..28aacd6 100644
--- a/examples/express/eslint.config.mjs
+++ b/examples/express/eslint.config.mjs
@@ -1,15 +1,43 @@
import examplesConfig from "../eslint.config.mjs";
import asosConfigReact from "../../peripheral/eslint-config-asosconfig/react.js";
import asosConfigServer from "../../peripheral/eslint-config-asosconfig/server.js";
+import parser from "@typescript-eslint/parser";
+import globals from "globals";
export default [
...[...asosConfigReact, ...asosConfigServer].map((config) => ({
- files: ["**/*.js"],
+ files: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"],
...config,
settings: {
+ "import/resolver": {
+ typescript: {
+ alwaysTryTypes: true,
+ project: "./src/routes/parallel-folder-convention/tsconfig.json"
+ }
+ },
react: {
version: "detect"
}
+ },
+ rules: {
+ ...config.rules,
+ "react/prop-types": "off",
+ "prettier/prettier": [
+ "error",
+ {
+ trailingComma: "none",
+ endOfLine: "auto"
+ }
+ ]
+ },
+ languageOptions: {
+ ...config.languageOptions,
+ parser,
+ globals: {
+ CLIENT: "readonly",
+ ...globals.browser,
+ ...globals.node
+ }
}
})),
...examplesConfig,
diff --git a/examples/express/package.json b/examples/express/package.json
index 4894627..a45185b 100644
--- a/examples/express/package.json
+++ b/examples/express/package.json
@@ -20,23 +20,29 @@
"lint:docs": "eslint *.md --flag unstable_config_lookup_from_file"
},
"dependencies": {
- "@asos/web-toggle-point-react-pointcuts": "file:../../packages/react-pointcuts",
"@asos/web-toggle-point-features": "file:../../packages/features",
+ "@asos/web-toggle-point-react-pointcuts": "file:../../packages/react-pointcuts",
"@asos/web-toggle-point-ssr": "file:../../packages/ssr",
"@asos/web-toggle-point-webpack": "file:../../packages/webpack",
+ "@reduxjs/toolkit": "^2.8.2",
"cross-env": "^7.0.3",
"express": "^4.17.1",
"http-status-codes": "^2.3.0",
"react": ">=17",
- "react-dom": ">=17"
+ "react-dom": ">=17",
+ "react-redux": "^9.2.0",
+ "valtio": "^2.1.5"
},
"devDependencies": {
"babel-loader": "^9.2.1",
"css-loader": "^7.1.2",
+ "enhanced-tsconfig-paths-webpack-plugin": "^0.2.3",
"mini-css-extract-plugin": "^2.9.2",
"path-exists-cli": "^2.0.0",
"prop-types": "^15.7.2",
+ "source-map-loader": "^5.0.0",
"style-loader": "^4.0.0",
+ "ts-loader": "^9.5.2",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.2",
"webpack-node-externals": "^3.0.0"
diff --git a/examples/express/src/index.js b/examples/express/src/index.js
index 11fa87e..1594241 100644
--- a/examples/express/src/index.js
+++ b/examples/express/src/index.js
@@ -1,12 +1,14 @@
import express from "express";
import animalsRouter from "./routes/animals/router.js";
import configRouter from "./routes/config/router.js";
+import parallelFolderConventionRouter from "./routes/parallel-folder-convention/router.tsx";
const app = express();
const PORT = process.env.PORT;
app.use("/animals", animalsRouter);
app.use("/config", configRouter);
+app.use("/parallel-folder-convention", parallelFolderConventionRouter);
app.get("/", (_, response) => {
response.send(`
@@ -39,6 +41,7 @@ app.get("/", (_, response) => {