Skip to content

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

Open
atuttle wants to merge 46 commits intomainfrom
feat/modernize
Open

v4.0.0 - Modern CFScript, no jQuery, no LessCSS, no Bootstrap, latest TestBox#453
atuttle wants to merge 46 commits intomainfrom
feat/modernize

Conversation

@atuttle
Copy link
Owner

@atuttle atuttle commented Feb 1, 2026

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

Breaking changes! ⚠️

... but no 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.

I was testing against Lucee 5.x because that's the earliest CFML engine I have at my disposal easily 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.

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.

In theory, everything's ready for production. I've done some poking around and it seeeeems fine. I'm going to plug it in at work and see if anything goes boom. It would be really nice if others could try it in low-stakes projects too, hence the beta release.

atuttle and others added 12 commits January 31, 2026 18:03
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
@netlify
Copy link

netlify bot commented Feb 1, 2026

Deploy Preview for taffy-docs canceled.

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

Copy link

@github-actions github-actions bot left a comment

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 22 commits February 12, 2026 13:55
m.cacheGetTime was computed as (startTime - endTime), producing a
negative value. All other timing metrics in the same function use
(endTime - startTime). This aligns cacheGetTime with that pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
onRequestStart and onRequest both had duplicated dashboard handling
with divergent behavior: onRequestStart checked
showDocsWhenDashboardDisabled == false (inverted), missing the
code path to actually show docs. onRequest had the correct logic.

Extract into handleDashboardRequest() called from both sites.
Fixes the case where dashboard is disabled but docs should be shown.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The polyfill delegates to qToArray() which returns an array, but
the function signature declared struct as the return type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Railo has been dead since ~2015 (succeeded by Lucee). Remove the
structKeyExists(server, "railo") checks in resource.cfc and update
the comment in api.cfc to reference Lucee instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
Ensure function calls match the function's signature.
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