Skip to content

v4.0.0 - Modern CFScript, no jQuery, no LessCSS, no Bootstrap, latest TestBox - #453

Merged
atuttle merged 54 commits into
mainfrom
feat/modernize
Apr 23, 2026
Merged

v4.0.0 - Modern CFScript, no jQuery, no LessCSS, no Bootstrap, latest TestBox#453
atuttle merged 54 commits into
mainfrom
feat/modernize

Conversation

@atuttle

@atuttle atuttle commented Feb 1, 2026

Copy link
Copy Markdown
Owner

*Checks watch*... It's been a minute. Hi.

Breaking changes! ⚠️

... but no breaking functional changes. 🧐 The only intentional breaking change is dropping support for older CFML engines/versions.

This release is a COMPLETE REWRITE of almost the entire codebase. In the process, we're finally stepping away from support for Adobe ColdFusion 8. If you're still on that version, God help you.

Testing against Lucee 5, 6, and 7 because that's what's easily tested on :octocat: right now. In theory it should be compatible with ACF 2016+, possibly earlier. If anyone wants to figure out what the minimum capable ACF version is, that would be nice.

  • All CFC's have migrated to full-cfscript
  • jQuery, Bootstrap, and LessCSS have all been removed in favor of vanilla JS+CSS (dashboard UI)
  • Test suite completely rewritten and updated to latest version of Testbox
  • Dashboard design overhauled... It's the same, but different.
  • Added OpenAPI / swagger.json support

Rewrite methodology

  1. The tests were updated first, without modifying any framework code, and all passed.
  2. Then the framework was updated without modifying any test code, and all tests passed.
  3. Then changes like redesigning the dashboard and rewriting dashboard JS were done.

We've been running in production at AlumnIQ for several months with zero issues.

@netlify

netlify Bot commented Feb 1, 2026

Copy link
Copy Markdown

Deploy Preview for taffy-docs canceled.

Name Link
🔨 Latest commit b5ed808
🔍 Latest deploy log https://app.netlify.com/projects/taffy-docs/deploys/69ea1eb7a80a0c0008e00e73

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pull request does not contain a valid label. Please add one of the following labels: ['Semver-Major', 'Semver-Minor', 'Semver-Patch']

@atuttle atuttle added the Semver-Major This change will necessitate a major version bump label Feb 1, 2026
atuttle and others added 24 commits April 10, 2026 09:57
Move existing MXUnit-based test suite to tests.bak.lol directory and
rename all .cfc/.cfm files to append .lol to disable them. This
preserves the old tests for reference while preparing for new
TestBox-based test infrastructure.

Archived directories:
- tests/tests/ (test cases)
- tests/resources/ (test resource CFCs)
- tests/resourcesError/
- tests/lib/ (bugLog, di1, Hoth dependencies)
- tests/someFolder/

Simplified tests/Application.cfc to remove references to archived
directories.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
don't need this wrapper class TestableResource that exposed private
functions
Lucee 6 and 7 seem to treat paths differently
I think this will fix the Lucee 7 failing tests
atuttle and others added 23 commits April 10, 2026 10:05
noData() previously read application._taffy.settings.noDataSends204NoContent
directly, coupling the serializer to the framework's application scope and
making standalone unit testing require mocking that scope.

Add a noDataSends204NoContent instance variable (default false) with a
setter. newRepresentation() and getRepInstance() now inject the setting
when creating serializer instances. Tests updated to use the setter
instead of mocking application scope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests were placeholders (expect(true).toBeTrue() or testing local
struct literals instead of framework behavior). Now bootstraps a real
api instance via onApplicationStart() and verifies actual defaults
from setupFramework(): reloadKey, reloadPassword, disableDashboard,
serializer/deserializer paths, CORS, ETags, JSONP, globalHeaders,
exceptionLogAdapter, version, unhandledPaths regex, and content types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a test API app (tests/testapi/) with echo resources and an e2e
test spec that makes real HTTP requests against the running server.

Covers: GET/POST/PUT/DELETE, URI token extraction, multi-token URIs,
JSON body deserialization, custom response headers, 404 for unknown
URIs, 405 for unsupported methods, and X-HTTP-Method-Override tunneling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
evaluate() is a known anti-pattern (potential injection vector, harder
to debug, worse performance). Use invoke() instead, which is the
modern CFML approach. Also removes stale CF8 compatibility comment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The code has defaulted to LogToDevNull but docs for 4.0.0 and @next
still said LogToEmail. Updated the default value and description text
in both files. Historical version docs left as-is.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Taffy's guessResourcesPath() checks expandPath('/resources') first.
Without a mapping, the resources directory wasn't found in CI,
causing all e2e tests to get 404s.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lucee 5 cfhttp can return fileContent as a byte array instead of a
string. Added isBinary check with toString coercion before isJSON.
Also added output=false to all test resource components and methods
to prevent whitespace leakage into response bodies.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Lucee 7: getDirectoryFromPath() on a path ending in / returns the
same path instead of the parent. Fix rootPath calculation by stripping
trailing slash first. Add /taffy mapping to testapi Application.cfc
since cfconfig is unavailable on Lucee 7 CI.

Lucee 5: Add charset=utf-8 to cfhttp to force string response.
Use toString() fallback for non-simple values, and trim() before
isJSON() check. Remove reloadOnEveryRequest from testapi.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. handleDashboardRequest: was infinite recursion (called itself).
   Ported dashboard/docs/redirect/403 logic from old tag-based code.

2. getDeserialized: invoke() needs a component object, not a string
   path. Also now checks factory for bean name before createObject,
   matching the pattern used by inspectMimeTypes/newRepresentation.

3. isInstanceOf("taffy.core.baseSerializer") returns false on Lucee
   because extends="baseSerializer" resolves to "core.baseSerializer"
   (relative), not the mapping-prefixed path. This caused every
   resource response to be re-wrapped via rep(), producing empty {}.
   Replaced with isSerializerInstance() metadata traversal helper.

Also fixed getSupportedContentTypes to support bean-name deserializers
via the same factory-or-createObject pattern.

All 234 tests pass on Lucee 5, 6, and 7.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
isInstanceOf(obj, "taffy.core.baseSerializer") returns false on Luceee
because extends resolves to a relative path instead of the
mapping-prefixed path. Replace with isSerializerInstance() metadata
traversal helper, matching the fix already applied in api.cfc (3af69e5).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CFConfig applies the /Taffy CFML mapping from .cfconfig.json on Lucee
5/6 but is uninstalled for Lucee 7 (unsupported). Without the mapping,
extends="taffy.core.api" in Application.cfc can't resolve at compile
time, causing every e2e request to return Lucee's default 500 HTML error
page.

Create a taffy symlink in the webroot so the component path resolves
naturally via the filesystem.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…isclosure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@atuttle

atuttle commented Apr 10, 2026

Copy link
Copy Markdown
Owner Author

Planning to land this PR with no further changes on Monday, 4/13.

@atuttle
atuttle merged commit b5ed808 into main Apr 23, 2026
9 checks passed
@atuttle
atuttle deleted the feat/modernize branch April 23, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Semver-Major This change will necessitate a major version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants