Skip to content

start emitting declarations during the build - extracted from the JS files#417

Merged
NullVoxPopuli merged 1 commit intomasterfrom
emit-types
Mar 25, 2026
Merged

start emitting declarations during the build - extracted from the JS files#417
NullVoxPopuli merged 1 commit intomasterfrom
emit-types

Conversation

@mansona
Copy link
Copy Markdown
Contributor

@mansona mansona commented Mar 24, 2026

We don't need to convert this project to TS to get it to start emitting some useful types 🎉

Here is an example of what it is generating straight from the JS with no JSDoc @type comments anywhere:

declare const _default: Readonly<Readonly<typeof import("@ember/-internals/glimmer/lib/helper").default> & (new (owner?: import("@ember/-internals/owner").default) => import("@ember/-internals/glimmer/lib/helper").default<unknown>) & {
    moment: PropertyDecorator;
    disableInterval: boolean;
    readonly globalAllowEmpty: any;
    supportsGlobalAllowEmpty: boolean;
    localeOrTimeZoneChanged: () => void;
    compute(value: any, { interval }: {
        interval: any;
    }): void;
    morphMoment(time: any, { locale, timeZone }: {
        locale: any;
        timeZone: any;
    }): any;
    clearTimer(): void;
    destroy(...args: any[]): void;
}> & (new (owner?: import("@ember/-internals/owner").default) => import("@ember/-internals/glimmer/lib/helper").default<unknown>) & {
    defaultFormatDidChange: () => void;
    compute: (params: any, hash: any, ...args: any[]) => any;
};
export default _default;
//# sourceMappingURL=moment-format.d.ts.map

Let me know if you have any questions or objections 👍

Edit: I bumped the node version used in CI (from the volta definition in pacakge.json) because of require(esm) problems and it's not relevant to the deployed v2 addon 👍

Edit: I fixed CI last night with other PRs and releases 👍 this should be ready to review+merge

@mansona
Copy link
Copy Markdown
Contributor Author

mansona commented Mar 24, 2026

@coderabbitai pause

@adopted-ember-addons adopted-ember-addons deleted a comment from coderabbitai bot Mar 24, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
ember-moment/tsconfig.json (1)

3-18: Make the unpublished-development-types contract explicit.

With rootDir pinned to ./src, TypeScript errors when an included non-declaration source file lives outside that tree. If this directory is intended to stay ambient-only, narrowing the glob to ./unpublished-development-types/**/*.d.ts would encode that invariant and avoid a future TS6059 footgun. (typescriptlang.org)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ember-moment/tsconfig.json` around lines 3 - 18, The tsconfig.json currently
includes "./unpublished-development-types/**/*" while rootDir is set to "./src",
which causes TS6059 if non-declaration files live outside src; narrow the
include to only declaration files by changing the include entry referencing
"unpublished-development-types" to "./unpublished-development-types/**/*.d.ts"
so that the compiler treats that directory as ambient-only and avoids conflicts
with the "rootDir" setting (update the "include" array entry in tsconfig.json
that references unpublished-development-types).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ember-moment/package.json`:
- Around line 18-22: Add an explicit JS-only export entry for the "./_app_/*"
paths before the existing "./*" export in the package.json "exports" block so
TypeScript won't match "./_app_/*" into the wildcard and incorrectly advertise
declarations; specifically, carve out "./_app_/*" with only a runtime/default
export (no "types" entry) and place it above the "./*" mapping that currently
provides "types": "./declarations/*.d.ts" and "default": "./dist/*.js" to ensure
declarations from "declarations/" are not (falsely) applied to _app_ artifacts.

In `@ember-moment/rollup.config.mjs`:
- Around line 56-57: Update the TypeScript declaration-generation command used
by addon.declarations to include --emitDeclarationOnly so tsc only emits .d.ts
files and does not produce JS that conflicts with Rollup/Babel; locate the call
addon.declarations('declarations', 'tsc --declaration') and change the command
string to include --emitDeclarationOnly (e.g., 'tsc --declaration
--emitDeclarationOnly').

---

Nitpick comments:
In `@ember-moment/tsconfig.json`:
- Around line 3-18: The tsconfig.json currently includes
"./unpublished-development-types/**/*" while rootDir is set to "./src", which
causes TS6059 if non-declaration files live outside src; narrow the include to
only declaration files by changing the include entry referencing
"unpublished-development-types" to "./unpublished-development-types/**/*.d.ts"
so that the compiler treats that directory as ambient-only and avoids conflicts
with the "rootDir" setting (update the "include" array entry in tsconfig.json
that references unpublished-development-types).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 108e5774-6ae2-4c80-a1ac-c61116ee3d4c

📥 Commits

Reviewing files that changed from the base of the PR and between e2514a4 and cd9eabf.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (3)
  • ember-moment/package.json
  • ember-moment/rollup.config.mjs
  • ember-moment/tsconfig.json

Comment on lines +18 to +22
"./addon-main.js": "./addon-main.cjs",
"./*": {
"types": "./declarations/*.d.ts",
"default": "./dist/*.js"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and read the package.json file
find . -name "package.json" -type f | head -20

Repository: adopted-ember-addons/ember-moment

Length of output: 203


🏁 Script executed:

# Read the main package.json to inspect the export map
cat -n ./package.json | head -100

Repository: adopted-ember-addons/ember-moment

Length of output: 1435


🏁 Script executed:

# Read the ember-moment/package.json file which is the one being reviewed
cat -n ./ember-moment/package.json

Repository: adopted-ember-addons/ember-moment

Length of output: 4987


🏁 Script executed:

# Check the tsconfig.json to understand declaration generation
cat -n ./ember-moment/tsconfig.json

Repository: adopted-ember-addons/ember-moment

Length of output: 897


🏁 Script executed:

# Check the build output and directory structure
ls -la ./ember-moment/dist/ 2>/dev/null || echo "dist/ doesn't exist yet"
ls -la ./ember-moment/declarations/ 2>/dev/null || echo "declarations/ doesn't exist yet"

Repository: adopted-ember-addons/ember-moment

Length of output: 132


🏁 Script executed:

# Check the rollup configuration to understand the build output structure
cat -n ./ember-moment/rollup.config.mjs | head -80

Repository: adopted-ember-addons/ember-moment

Length of output: 3043


🏁 Script executed:

# Let's check if there's a build output or if we can inspect the src directory structure
ls -la ./ember-moment/src/ | head -30

Repository: adopted-ember-addons/ember-moment

Length of output: 415


🏁 Script executed:

# Let's check what files are in the src/helpers and src/services directories
find ./ember-moment/src -type f -name "*.js" -o -name "*.gjs" | head -20

Repository: adopted-ember-addons/ember-moment

Length of output: 918


🌐 Web query:

TypeScript package.json exports longest prefix pattern matching module resolution

💡 Result:

TypeScript's module resolution for package.json "exports" field uses longest prefix pattern matching, analogous to its "paths" mapping resolution. In TypeScript's module resolution (under moduleResolution: "node16", "nodenext", or "bundler"), when resolving an import specifier against a package's "exports" map, it selects the export key with the longest matching prefix for the subpath. This matches Node.js's PACKAGE_EXPORTS_RESOLVE algorithm, which iterates over exports keys (in package.json object order) and uses the first (longest-matching) subpath pattern or exact match. For subpath patterns (keys ending in ""), matching replaces "" with the corresponding suffix from the requested subpath. TypeScript prioritizes "exports" over legacy fields like "typesVersions", "types", and "main" when present. To enable: Use "moduleResolution": "node16"/"nodenext"/"bundler" and "resolvePackageJsonExports": true (default in those modes). Example package.json: { "exports": { ".": "./index.js", "./foo": "./foo.js", "./bar/": "./bar/.js" } } Import "pkg/bar/baz" matches "./bar/*" (longest prefix "./bar/" > "."). This prevents access to unexported subpaths, enforcing encapsulation.

Citations:


Add explicit ./_app_/* export to prevent false type advertisements.

The wildcard ./* export pattern matches _app_/* paths (from ember-addon.app-js), but TypeScript's longest-prefix matching means if ./_app_/* is defined, it takes precedence. Currently, the ./* pattern advertises declarations/_app_/**.d.ts types that won't be generated—the build only creates declarations from src/ (via tsconfig.json's rootDir: "./src"), not from the _app_/ build artifact. Add an explicit JS-only ./_app_/* export before ./* to carve those paths out cleanly and prevent false type resolution.

📦 Suggested change
   "exports": {
     ".": {
       "types": "./declarations/index.d.ts",
       "default": "./dist/index.js"
     },
     "./addon-main.js": "./addon-main.cjs",
+    "./_app_/*": "./dist/_app_/*.js",
     "./*": {
       "types": "./declarations/*.d.ts",
       "default": "./dist/*.js"
     }
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"./addon-main.js": "./addon-main.cjs",
"./*": {
"types": "./declarations/*.d.ts",
"default": "./dist/*.js"
}
"./addon-main.js": "./addon-main.cjs",
"./_app_/*": "./dist/_app_/*.js",
"./*": {
"types": "./declarations/*.d.ts",
"default": "./dist/*.js"
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ember-moment/package.json` around lines 18 - 22, Add an explicit JS-only
export entry for the "./_app_/*" paths before the existing "./*" export in the
package.json "exports" block so TypeScript won't match "./_app_/*" into the
wildcard and incorrectly advertise declarations; specifically, carve out
"./_app_/*" with only a runtime/default export (no "types" entry) and place it
above the "./*" mapping that currently provides "types": "./declarations/*.d.ts"
and "default": "./dist/*.js" to ensure declarations from "declarations/" are not
(falsely) applied to _app_ artifacts.

Comment on lines +56 to +57
// Emit .d.ts declaration files
addon.declarations('declarations', 'tsc --declaration'),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if the file exists and examine it
find . -name "rollup.config.mjs" -type f

Repository: adopted-ember-addons/ember-moment

Length of output: 109


🏁 Script executed:

# Read the rollup.config.mjs file to understand context
cat -n ember-moment/rollup.config.mjs 2>/dev/null || find . -name "rollup.config.mjs" -exec cat -n {} +

Repository: adopted-ember-addons/ember-moment

Length of output: 3043


🏁 Script executed:

# Look for package.json to understand dependencies
find . -name "package.json" -type f | head -5

Repository: adopted-ember-addons/ember-moment

Length of output: 203


🏁 Script executed:

# Check for tsconfig files
find . -name "tsconfig.json" -type f

Repository: adopted-ember-addons/ember-moment

Length of output: 105


🏁 Script executed:

# Read the main tsconfig.json
cat -n tsconfig.json 2>/dev/null || cat -n ./ember-moment/tsconfig.json 2>/dev/null || find . -name "tsconfig.json" -exec cat -n {} +

Repository: adopted-ember-addons/ember-moment

Length of output: 897


🌐 Web query:

TypeScript emitDeclarationOnly --declaration allowJs documentation

💡 Result:

The TypeScript compiler options --emitDeclarationOnly, --declaration, and allowJs work together to generate declaration files (.d.ts) from JavaScript files without emitting JavaScript output. Key points: - emitDeclarationOnly: true (or --emitDeclarationOnly): Instructs the compiler to only emit .d.ts files, skipping .js files. Useful when using another transpiler for JS or providing types for consumers. - declaration: true (or --declaration): Enables generation of .d.ts files. Required when using emitDeclarationOnly. - allowJs: true (or --allowJs): Allows the compiler to process .js files as part of the program, enabling type checking and declaration generation from them. To generate .d.ts files from .js files: 1. Create a tsconfig.json: { "compilerOptions": { "allowJs": true, "declaration": true, "emitDeclarationOnly": true, "outDir": "dist" // Optional: directs output to a separate directory }, "include": ["src//.js"] } 2. Run tsc (uses tsconfig.json) or CLI: tsc src//.js --allowJs --declaration --emitDeclarationOnly --outDir dist. This setup processes .js files (thanks to allowJs), generates corresponding .d.ts files (via declaration + emitDeclarationOnly), and avoids overwriting original .js files (use outDir). Examples from docs: - CLI: tsc index.js --declaration --emitDeclarationOnly - For JS projects incrementally adopting TS. Note: Cannot combine emitDeclarationOnly with noEmit. For jsconfig.json projects, there may be compatibility issues with --emitDeclarationOnly. Official docs confirm this combination for creating .d.ts from .js files, especially with JSDoc for better types.

Citations:


Add --emitDeclarationOnly to the declaration generation command.

This build uses Rollup/Babel to emit JavaScript. When TypeScript generates declarations from JavaScript with allowJs enabled, it should run in declaration-only mode to avoid emitting JavaScript that would conflict with Rollup's output. TypeScript's documentation explicitly recommends pairing --declaration with --emitDeclarationOnly in this scenario.

Suggested change
-    addon.declarations('declarations', 'tsc --declaration'),
+    addon.declarations('declarations', 'tsc --declaration --emitDeclarationOnly'),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Emit .d.ts declaration files
addon.declarations('declarations', 'tsc --declaration'),
// Emit .d.ts declaration files
addon.declarations('declarations', 'tsc --declaration --emitDeclarationOnly'),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ember-moment/rollup.config.mjs` around lines 56 - 57, Update the TypeScript
declaration-generation command used by addon.declarations to include
--emitDeclarationOnly so tsc only emits .d.ts files and does not produce JS that
conflicts with Rollup/Babel; locate the call addon.declarations('declarations',
'tsc --declaration') and change the command string to include
--emitDeclarationOnly (e.g., 'tsc --declaration --emitDeclarationOnly').

@adopted-ember-addons adopted-ember-addons deleted a comment from coderabbitai bot Mar 24, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

TypeScript support is being added to the ember-moment addon through updated package exports with type definitions, new TypeScript configuration, modified build process to generate declarations, updated development dependencies, and upgraded Node.js version. An import pattern in the test application is simplified.

Changes

Cohort / File(s) Summary
TypeScript Setup
ember-moment/tsconfig.json, ember-moment/rollup.config.mjs, ember-moment/package.json exports
Added TypeScript configuration extending @ember/library-tsconfig, configured to emit declarations to declarations/ directory; modified rollup build to generate type declarations via tsc --declaration instead of retaining CSS assets; updated package.json exports map to include types field pointing to ./declarations/index.d.ts and ./declarations/*.d.ts.
Development Toolchain
ember-moment/package.json devDependencies, package.json volta
Updated @embroider/addon-dev from ^4.3.1 to ^8.3.0, added @ember/library-tsconfig, ember-source, and typescript to devDependencies; bumped Volta-pinned Node.js version from 18.20.3 to 24.14.1.
Application Code
test-app-3.x/app/controllers/index.js
Simplified @ember/service import from compatibility fallback pattern (service ?? inject) to direct named import of inject as service.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Whiskers twitching with TypeScript delight,
Declarations generated, types shining bright,
Build pipes configured, Node leveled up high,
Ember-moment hops forward beneath the blue sky!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title accurately describes the main objective of the changeset—enabling TypeScript declaration file emission during the build from JavaScript source files.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch emit-types

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@package.json`:
- Line 25: You changed the Node engine to "24.14.1" in package.json (the "node"
engines entry); before committing, verify all dependencies and CI/tools support
Node 24, run full test suites and linting under Node 24, update any
incompatibility (bump or pin offending packages) or revert to a compatible range
(e.g., maintain >=18 until ready), and if this is intentional add a migration
note to CONTRIBUTING.md or the PR describing required local setup and any
breaking changes to help contributors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 36ea9fb7-1cd4-4c20-8949-ed2dbba31ee4

📥 Commits

Reviewing files that changed from the base of the PR and between e2514a4 and 9290fa1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (5)
  • ember-moment/package.json
  • ember-moment/rollup.config.mjs
  • ember-moment/tsconfig.json
  • package.json
  • test-app-3.x/app/controllers/index.js

},
"volta": {
"node": "18.20.3",
"node": "24.14.1",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Node.js 24 release date LTS

💡 Result:

Node.js 24 was released on May 6, 2025, as the initial Current release (v24.0.0). It entered Active LTS status on October 28, 2025, with v24.11.0. As of March 24, 2026, it is in Active LTS (codename Krypton), with Active LTS until October 20, 2026, Maintenance LTS until April 30, 2028, and full EOL on April 30, 2028.

Citations:


Ensure Node.js 24 compatibility across dependencies before major version upgrade.

Node.js 24 is now in Active LTS (since October 2025) and 24.14.1 is a valid, supported version. However, this represents a jump of 6 major versions from Node 18. Before committing to this upgrade, verify that:

  • All project dependencies support Node 24 without breaking changes
  • Contributors' local environments can reasonably support Node 24
  • Breaking changes between Node 18 and 24 don't impact the codebase

If this change is intentional for a major version bump, add a clear migration guide or update CONTRIBUTING.md accordingly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` at line 25, You changed the Node engine to "24.14.1" in
package.json (the "node" engines entry); before committing, verify all
dependencies and CI/tools support Node 24, run full test suites and linting
under Node 24, update any incompatibility (bump or pin offending packages) or
revert to a compatible range (e.g., maintain >=18 until ready), and if this is
intentional add a migration note to CONTRIBUTING.md or the PR describing
required local setup and any breaking changes to help contributors.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 24, 2026

✅ Actions performed

Reviews paused.

@mansona mansona changed the title start emitting declarations during the build start emitting declarations during the build - extracted from the JS files Mar 25, 2026
Copy link
Copy Markdown
Collaborator

@NullVoxPopuli NullVoxPopuli left a comment

Choose a reason for hiding this comment

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

seems fine

@NullVoxPopuli NullVoxPopuli merged commit 2059587 into master Mar 25, 2026
18 checks passed
@NullVoxPopuli NullVoxPopuli deleted the emit-types branch March 25, 2026 14:04
@github-actions github-actions bot mentioned this pull request Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants