rolldown-plugin-angularjs-annotate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gilles Piou
4
+ Copyright (c) 2013-2016 Olov Lassus <olov.lassus@gmail.com>
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,16 @@
1
+ This project includes an independent ESTree/MagicString adaptation of matching
2
+ behavior and tests from:
3
+
4
+ - babel-plugin-angularjs-annotate by schmod
5
+ https://github.com/schmod/babel-plugin-angularjs-annotate
6
+ - ng-annotate by Olov Lassus and contributors
7
+ https://github.com/olov/ng-annotate
8
+
9
+ The original ng-annotate copyright is:
10
+
11
+ Copyright (c) 2013-2016 Olov Lassus <olov.lassus@gmail.com>
12
+
13
+ Both upstream projects are distributed under the MIT License. The upstream
14
+ copyright is retained in this project's LICENSE. The development test suite
15
+ loads the published babel-plugin-angularjs-annotate@0.10.0 fixtures directly;
16
+ those fixture files are not included in this package's published files.
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # rolldown-plugin-angularjs-annotate
2
+
3
+ AngularJS dependency-injection annotations for Rolldown, without a Babel
4
+ transform layer.
5
+
6
+ This package ports the supported annotation behavior of
7
+ `babel-plugin-angularjs-annotate@0.10.0` to Rolldown. Its complete active corpus
8
+ of 131 fixtures across 11 suites is checked in the upstream project's enabled
9
+ original-source and Babel-transpiled ES5 modes, including context-sensitive
10
+ negative cases and `explicitOnly`.
11
+
12
+ ## Install
13
+
14
+ Requires Node.js `>=22.12.0` and Rolldown `^1.2.0`.
15
+
16
+ ```sh
17
+ npm install --save-dev rolldown-plugin-angularjs-annotate
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```js
23
+ const angularjsAnnotate = require('rolldown-plugin-angularjs-annotate');
24
+
25
+ module.exports = {
26
+ plugins: [angularjsAnnotate()]
27
+ };
28
+ ```
29
+
30
+ The plugin uses Rolldown's filtered transform hook and native AST/MagicString
31
+ metadata when available. It runs in the `post` phase so framework plugins can
32
+ turn virtual modules, such as Vue single-file component scripts, into
33
+ JavaScript first.
34
+
35
+ This is a Rolldown plugin. Its package metadata deliberately marks Rollup as
36
+ incompatible rather than claiming support for an untested fallback host.
37
+
38
+ ## Options
39
+
40
+ ```js
41
+ angularjsAnnotate({
42
+ include: ['**/src/**/*.js', '**/src/**/*.ts'],
43
+ exclude: '**/*.spec.js',
44
+ explicitOnly: false,
45
+ regexp: '^app(?:\\..+)?$'
46
+ });
47
+ ```
48
+
49
+ | Option | Meaning |
50
+ | --- | --- |
51
+ | `include` | String glob, `RegExp`, or array of either. Defaults to JavaScript/TypeScript IDs and modules Rolldown identifies as JavaScript/TypeScript, including framework-generated virtual modules. |
52
+ | `exclude` | String glob, `RegExp`, or array of either. Defaults to `node_modules` and Rolldown's runtime module. |
53
+ | `explicitOnly` | When `true`, only `@ngInject`, `ngInject`, and their no-inject counterparts are considered. |
54
+ | `regexp` | Restricts source expressions accepted as implicit module receivers, such as `app` or `require("app-module")`. Explicit `angular.module(...)` chains remain recognized. The compatibility default accepts identifier and dotted-property forms. |
55
+
56
+ Use `regexp: '^$'` to disable implicit receiver matching while retaining explicit
57
+ `angular.module(...)` chains.
58
+
59
+ ## Supported annotations
60
+
61
+ Explicit annotation supports:
62
+
63
+ - `@ngInject` and `@ngNoInject` line, block, and JSDoc comments
64
+ - `"ngInject"` and `"ngNoInject"` directive prologues
65
+ - `ngInject(value)` and `ngNoInject(value)` wrappers
66
+ - functions, arrows, classes, constructors, assignments, references, exports,
67
+ object properties, and recursively annotated object literals
68
+
69
+ Implicit matching supports:
70
+
71
+ - long and short AngularJS module registrations and chains
72
+ - controllers, services, factories, filters, directives, providers,
73
+ decorators, animations, components, config/run blocks, invoke, and store
74
+ - component controllers/templates and directive definition objects
75
+ - provider `$get` declarations and reference following
76
+ - `$provide`, `$injector`, `$controllerProvider`, route/UI-Router providers,
77
+ HTTP interceptors, UI Bootstrap modals, and Angular Material overlays
78
+ - lexical binding resolution, shadowing, hoisting, aliases, and direct IIFEs
79
+
80
+ Existing inline arrays, `$inject` assignments, and static class `$inject`
81
+ fields are preserved. Unsupported destructured parameter lists are left
82
+ unchanged instead of producing positionally incorrect annotations. Ambiguous
83
+ mutable references and object methods that rely on `super` are also left
84
+ unchanged rather than receiving a transformation that could alter runtime
85
+ semantics.
86
+
87
+ ## Low-level API
88
+
89
+ Pipelines sharing an AST and MagicString instance can call the core directly:
90
+
91
+ ```js
92
+ const { annotate } = require('rolldown-plugin-angularjs-annotate');
93
+
94
+ annotate(program, code, magicString, {
95
+ comments,
96
+ explicitOnly: false
97
+ });
98
+ ```
99
+
100
+ The `comments` array is optional; the core has a source-based fallback for
101
+ native Rolldown ASTs. Public TypeScript declarations cover both the plugin and
102
+ the low-level API. `onWarn` receives a message and, when available, a diagnostic
103
+ with zero-based `start` and `end` source offsets. The plugin wrapper forwards
104
+ these as structured Rolldown warnings with the module ID and source position;
105
+ annotation and parser failures similarly use Rolldown's structured error API.
106
+
107
+ ## Verification
108
+
109
+ ```sh
110
+ npm run check
111
+ ```
112
+
113
+ The suite includes 508 semantic comparisons against the upstream compatibility
114
+ corpus, safety regressions, a minified AngularJS `strictDi` bootstrap, source
115
+ maps, filters, TypeScript/Vue module IDs, framework-generated modules with
116
+ non-script IDs, package consumer types, and real Rolldown builds with native
117
+ MagicString both disabled and enabled. Babel is a development-only fixture
118
+ preprocessor for the ES5 compatibility lane; published transforms use
119
+ Rolldown's parser and do not add a Babel transform layer.
120
+
121
+ ## AI disclosure
122
+
123
+ Developed entirely with OpenAI Codex (GPT-5.6 Sol, using Ultra and Extra High
124
+ reasoning effort).
125
+
126
+ ## License
127
+
128
+ MIT. See [NOTICE](NOTICE) for upstream attribution.
package/index.d.ts ADDED
@@ -0,0 +1,59 @@
1
+ import type MagicString from 'magic-string';
2
+ import type { Plugin, RolldownMagicString } from 'rolldown';
3
+ import type { ESTree } from 'rolldown/utils';
4
+
5
+ declare function angularjsAnnotate(
6
+ options?: angularjsAnnotate.AngularJSAnnotateOptions,
7
+ ): Plugin;
8
+
9
+ declare namespace angularjsAnnotate {
10
+ type FilterPattern = string | RegExp | readonly (string | RegExp)[];
11
+
12
+ interface AngularJSAnnotateOptions {
13
+ /** Module IDs transformed by the plugin. */
14
+ include?: FilterPattern;
15
+ /** Module IDs omitted by the plugin. */
16
+ exclude?: FilterPattern;
17
+ /** Disable all implicit AngularJS pattern matching. */
18
+ explicitOnly?: boolean;
19
+ /** Restrict source expressions accepted as implicit AngularJS module receivers. */
20
+ regexp?: string | RegExp;
21
+ }
22
+
23
+ interface ParserComment {
24
+ /** Accepted for compatibility with parser comment objects; annotation only uses the range and value. */
25
+ type?: string;
26
+ value: string;
27
+ start: number;
28
+ end: number;
29
+ }
30
+
31
+ interface AnnotateDiagnostic {
32
+ /** Stable diagnostic identifier suitable for filtering build logs. */
33
+ code?: string;
34
+ /** Zero-based source offsets when the diagnostic is tied to syntax. */
35
+ start?: number;
36
+ end?: number;
37
+ }
38
+
39
+ interface AnnotateOptions {
40
+ comments?: readonly ParserComment[] | null;
41
+ explicitOnly?: boolean;
42
+ regexp?: string | RegExp;
43
+ /** Receives the message and, when available, its source span. */
44
+ onWarn?: (message: string, diagnostic?: AnnotateDiagnostic) => void;
45
+ }
46
+
47
+ function annotate(
48
+ program: ESTree.Program,
49
+ code: string,
50
+ magicString: MagicString | RolldownMagicString,
51
+ options?: AnnotateOptions,
52
+ ): void;
53
+
54
+ const angularjsAnnotate: (
55
+ options?: AngularJSAnnotateOptions,
56
+ ) => Plugin;
57
+ }
58
+
59
+ export = angularjsAnnotate;
package/index.js ADDED
@@ -0,0 +1,103 @@
1
+ 'use strict';
2
+
3
+ const MagicString = require('magic-string');
4
+ const { parseSync } = require('rolldown/utils');
5
+ const annotate = require('./src/annotate');
6
+
7
+ const DEFAULT_EXCLUDE = [/(?:^|[/\\])node_modules[/\\]/, /\0rolldown[/\\]runtime\.js$/];
8
+
9
+ function angularjsAnnotate(options = {}) {
10
+ const { include, exclude = DEFAULT_EXCLUDE } = options;
11
+ const useModuleTypeFilter = include === undefined;
12
+
13
+ return {
14
+ name: 'rolldown-plugin-angularjs-annotate',
15
+ enforce: 'post',
16
+ transform: {
17
+ filter: useModuleTypeFilter ? {
18
+ id: { exclude },
19
+ moduleType: ['js', 'jsx', 'ts', 'tsx'],
20
+ } : { id: { include, exclude } },
21
+ handler(code, id, meta = {}) {
22
+ let parsed;
23
+ try {
24
+ parsed = meta.ast ? { program: meta.ast, comments: null, errors: [] } : parseSync(id, code, {
25
+ lang: language(id, meta.moduleType),
26
+ sourceType: 'unambiguous',
27
+ });
28
+ } catch (error) {
29
+ reportError(this, error, id);
30
+ }
31
+ if (parsed.errors.length) reportError(this, parserError(parsed.errors[0], id), id);
32
+
33
+ const magicString = meta.magicString || new MagicString(code);
34
+ try {
35
+ annotate(parsed.program, code, magicString, {
36
+ comments: parsed.comments,
37
+ explicitOnly: options.explicitOnly,
38
+ regexp: options.regexp,
39
+ onWarn: (message, diagnostic) => {
40
+ if (typeof this?.warn !== 'function') return;
41
+ this.warn({
42
+ message,
43
+ id,
44
+ pluginCode: diagnostic?.code || 'ANNOTATION_MISMATCH',
45
+ }, diagnosticPosition(diagnostic));
46
+ },
47
+ });
48
+ } catch (error) {
49
+ reportError(this, error, id);
50
+ }
51
+ if (!magicString.hasChanged()) return;
52
+
53
+ return meta.magicString ? { code: magicString } : {
54
+ code: magicString.toString(),
55
+ map: magicString.generateMap({ hires: 'boundary', includeContent: true, source: id }),
56
+ };
57
+ },
58
+ },
59
+ };
60
+ }
61
+
62
+ function language(id, moduleType) {
63
+ if (isJavaScriptModuleType(moduleType)) return moduleType;
64
+ const match = /(?:\.([cm]?[jt]sx?)(?:$|\?)|(?:^|[?&])lang\.([jt]sx?)(?:&|$))/.exec(id);
65
+ const extension = match?.[1] || match?.[2];
66
+ if (extension?.endsWith('tsx')) return 'tsx';
67
+ if (extension?.endsWith('ts')) return 'ts';
68
+ if (extension?.endsWith('jsx')) return 'jsx';
69
+ return 'js';
70
+ }
71
+
72
+ function isJavaScriptModuleType(moduleType) {
73
+ return moduleType === 'js' || moduleType === 'jsx' || moduleType === 'ts' || moduleType === 'tsx';
74
+ }
75
+
76
+ function parserError(diagnostic, id) {
77
+ const message = diagnostic?.message || diagnostic?.labels?.[0]?.message || String(diagnostic);
78
+ const error = new SyntaxError(message);
79
+ error.cause = diagnostic;
80
+ error.id = id;
81
+ error.pluginCode = 'PARSE_ERROR';
82
+ const position = diagnosticPosition(diagnostic);
83
+ if (position !== undefined) error.start = position;
84
+ return error;
85
+ }
86
+
87
+ function reportError(context, value, id) {
88
+ const error = value instanceof Error ? value : new Error(String(value));
89
+ if (error.id === undefined) error.id = id;
90
+ if (error.pluginCode === undefined) error.pluginCode = error.code || 'ANNOTATION_ERROR';
91
+ if (typeof context?.error === 'function') context.error(error, diagnosticPosition(error));
92
+ if (!error.message.startsWith(`${id}: `)) error.message = `${id}: ${error.message}`;
93
+ throw error;
94
+ }
95
+
96
+ function diagnosticPosition(diagnostic) {
97
+ const position = diagnostic?.start ?? diagnostic?.labels?.[0]?.start;
98
+ return Number.isInteger(position) && position >= 0 ? position : undefined;
99
+ }
100
+
101
+ module.exports = angularjsAnnotate;
102
+ module.exports.annotate = annotate;
103
+ module.exports.angularjsAnnotate = angularjsAnnotate;
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "rolldown-plugin-angularjs-annotate",
3
+ "version": "0.1.0",
4
+ "description": "AngularJS dependency injection annotations for Rolldown without a Babel transform layer",
5
+ "author": "Gilles Piou",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/pioug/rolldown-plugin-angularjs-annotate.git"
10
+ },
11
+ "homepage": "https://github.com/pioug/rolldown-plugin-angularjs-annotate#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/pioug/rolldown-plugin-angularjs-annotate/issues"
14
+ },
15
+ "type": "commonjs",
16
+ "main": "index.js",
17
+ "types": "index.d.ts",
18
+ "sideEffects": false,
19
+ "exports": {
20
+ ".": {
21
+ "types": "./index.d.ts",
22
+ "require": "./index.js",
23
+ "default": "./index.js"
24
+ },
25
+ "./core": {
26
+ "types": "./src/annotate.d.ts",
27
+ "require": "./src/annotate.js",
28
+ "default": "./src/annotate.js"
29
+ },
30
+ "./package.json": "./package.json"
31
+ },
32
+ "files": [
33
+ "index.js",
34
+ "index.d.ts",
35
+ "NOTICE",
36
+ "src"
37
+ ],
38
+ "scripts": {
39
+ "test": "node --test",
40
+ "test:parity": "node --test test/parity.test.js",
41
+ "test:unit": "node --test test/annotate.test.js test/angular-aliases.test.js test/binding-resolution.test.js test/markers.test.js test/nested-targets.test.js test/plugin.test.js test/typescript.test.js",
42
+ "typecheck": "tsc -p type-tests/tsconfig.json",
43
+ "lint:package": "publint",
44
+ "verify:package-contents": "node scripts/verify-package-contents.js",
45
+ "check": "npm run typecheck && npm test && npm run lint:package",
46
+ "prepublishOnly": "npm run check && npm run verify:package-contents"
47
+ },
48
+ "keywords": [
49
+ "angularjs",
50
+ "dependency-injection",
51
+ "ng-annotate",
52
+ "rolldown",
53
+ "rolldown-plugin"
54
+ ],
55
+ "engines": {
56
+ "node": ">=22.12.0"
57
+ },
58
+ "dependencies": {
59
+ "magic-string": "^0.30.21"
60
+ },
61
+ "peerDependencies": {
62
+ "rolldown": "^1.2.0"
63
+ },
64
+ "devDependencies": {
65
+ "@babel/core": "^7.29.7",
66
+ "@babel/preset-env": "^7.29.7",
67
+ "angular": "1.8.3",
68
+ "babel-plugin-angularjs-annotate": "0.10.0",
69
+ "publint": "^0.3.21",
70
+ "rolldown": "^1.2.0",
71
+ "typescript": "^5.9.3"
72
+ },
73
+ "compatiblePackages": {
74
+ "schemaVersion": 1,
75
+ "rollup": {
76
+ "type": "incompatible",
77
+ "reason": "Targets and tests Rolldown only and depends on Rolldown parser and plugin APIs"
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,3 @@
1
+ import angularjsAnnotate = require('../index');
2
+
3
+ export = angularjsAnnotate.annotate;