@hakobu/hakobu 1.0.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 +21 -0
- package/README.md +673 -0
- package/dictionary/angular-bridge.js +3 -0
- package/dictionary/any-promise.js +3 -0
- package/dictionary/async.js +3 -0
- package/dictionary/aws-sdk.js +7 -0
- package/dictionary/babel-core.js +3 -0
- package/dictionary/batch.js +3 -0
- package/dictionary/bcrypt.js +3 -0
- package/dictionary/better-sqlite3.js +3 -0
- package/dictionary/bignum.js +3 -0
- package/dictionary/bindings.js +3 -0
- package/dictionary/blessed.js +8 -0
- package/dictionary/body-parser.js +9 -0
- package/dictionary/browserify.js +7 -0
- package/dictionary/bson.js +3 -0
- package/dictionary/buffermaker.js +7 -0
- package/dictionary/bunyan.js +9 -0
- package/dictionary/busboy.js +7 -0
- package/dictionary/bytes.js +3 -0
- package/dictionary/callsites.js +3 -0
- package/dictionary/chokidar.js +3 -0
- package/dictionary/coffee-script.js +7 -0
- package/dictionary/colors.js +3 -0
- package/dictionary/compression.js +3 -0
- package/dictionary/compressjs.js +7 -0
- package/dictionary/connect-mongo.js +3 -0
- package/dictionary/connect-mongodb.js +3 -0
- package/dictionary/connect-redis.js +3 -0
- package/dictionary/connect.js +10 -0
- package/dictionary/consolidate.js +3 -0
- package/dictionary/cookie-parser.js +3 -0
- package/dictionary/cookie.js +3 -0
- package/dictionary/cors.js +3 -0
- package/dictionary/cron.js +3 -0
- package/dictionary/cross-env.js +11 -0
- package/dictionary/cross-spawn-async.js +3 -0
- package/dictionary/curve25519.js +3 -0
- package/dictionary/data-preflight.js +7 -0
- package/dictionary/debug.js +3 -0
- package/dictionary/denymount.js +3 -0
- package/dictionary/diff.js +3 -0
- package/dictionary/drivelist.js +22 -0
- package/dictionary/ed25519.js +3 -0
- package/dictionary/ejs.js +3 -0
- package/dictionary/elasticsearch.js +3 -0
- package/dictionary/electron.js +17 -0
- package/dictionary/emailjs.js +3 -0
- package/dictionary/engine.io.js +3 -0
- package/dictionary/epoll.js +3 -0
- package/dictionary/errorhandler.js +7 -0
- package/dictionary/errors.js +7 -0
- package/dictionary/eslint.js +7 -0
- package/dictionary/etcher-image-write.js +3 -0
- package/dictionary/exceljs.js +21 -0
- package/dictionary/exiftool.exe.js +13 -0
- package/dictionary/exiftool.pl.js +13 -0
- package/dictionary/express-load.js +12 -0
- package/dictionary/express-session.js +3 -0
- package/dictionary/express.js +14 -0
- package/dictionary/extender.js +11 -0
- package/dictionary/extsprintf.js +3 -0
- package/dictionary/faye-websocket.js +3 -0
- package/dictionary/feathers.js +3 -0
- package/dictionary/findup-sync.js +3 -0
- package/dictionary/floordate.js +3 -0
- package/dictionary/fmt.js +3 -0
- package/dictionary/formidable.js +3 -0
- package/dictionary/fs-extra.js +3 -0
- package/dictionary/fsevents.js +3 -0
- package/dictionary/geoip-lite.js +7 -0
- package/dictionary/github.js +7 -0
- package/dictionary/gm.js +3 -0
- package/dictionary/google-closure-compiler-java.js +13 -0
- package/dictionary/google-closure-compiler.js +13 -0
- package/dictionary/googleapis.js +7 -0
- package/dictionary/got.js +3 -0
- package/dictionary/graceful-fs.js +19 -0
- package/dictionary/grpc.js +11 -0
- package/dictionary/gulp.js +3 -0
- package/dictionary/hap-nodejs.js +3 -0
- package/dictionary/heapdump.js +3 -0
- package/dictionary/hoek.js +3 -0
- package/dictionary/homebridge.js +3 -0
- package/dictionary/http-proxy.js +3 -0
- package/dictionary/http-server.js +3 -0
- package/dictionary/image-size.js +3 -0
- package/dictionary/indexof.js +3 -0
- package/dictionary/inquirer.js +3 -0
- package/dictionary/j.js +16 -0
- package/dictionary/jade.js +3 -0
- package/dictionary/jsdom.js +3 -0
- package/dictionary/json-stringify-date.js +3 -0
- package/dictionary/json-stringify-safe.js +3 -0
- package/dictionary/jsonwebtoken.js +3 -0
- package/dictionary/kerberos.js +3 -0
- package/dictionary/knex.js +7 -0
- package/dictionary/later.js +7 -0
- package/dictionary/level.js +3 -0
- package/dictionary/leveldown.js +10 -0
- package/dictionary/levelup.js +3 -0
- package/dictionary/liftoff.js +12 -0
- package/dictionary/lodash.js +3 -0
- package/dictionary/log4js.js +7 -0
- package/dictionary/logform.js +7 -0
- package/dictionary/machinepack-urls.js +7 -0
- package/dictionary/markdown.js +3 -0
- package/dictionary/mdns.js +6 -0
- package/dictionary/method-override.js +3 -0
- package/dictionary/microjob.js +16 -0
- package/dictionary/mime-types.js +3 -0
- package/dictionary/mime.js +3 -0
- package/dictionary/minimatch.js +3 -0
- package/dictionary/minstache.js +3 -0
- package/dictionary/module-deps.js +3 -0
- package/dictionary/moment-timezone.js +3 -0
- package/dictionary/moment.js +7 -0
- package/dictionary/mongodb-core.js +22 -0
- package/dictionary/mongodb.js +7 -0
- package/dictionary/mongoose.js +7 -0
- package/dictionary/mongoskin.js +7 -0
- package/dictionary/ms.js +3 -0
- package/dictionary/msgpack.js +3 -0
- package/dictionary/multer.js +3 -0
- package/dictionary/muri.js +3 -0
- package/dictionary/native-or-bluebird.js +3 -0
- package/dictionary/natives.js +3 -0
- package/dictionary/nconf.js +7 -0
- package/dictionary/nedb.js +3 -0
- package/dictionary/negotiator.js +7 -0
- package/dictionary/newrelic.js +3 -0
- package/dictionary/nib.js +3 -0
- package/dictionary/nightmare.js +18 -0
- package/dictionary/node-forge.js +7 -0
- package/dictionary/node-libcurl.js +3 -0
- package/dictionary/node-notifier.js +30 -0
- package/dictionary/node-pre-gyp.js +7 -0
- package/dictionary/node-redis-pubsub.js +3 -0
- package/dictionary/node-sass.js +3 -0
- package/dictionary/node-uuid.js +3 -0
- package/dictionary/node-xlsx.js +3 -0
- package/dictionary/node-zookeeper-client.js +7 -0
- package/dictionary/nodegit.js +7 -0
- package/dictionary/nodemailer-sendmail-transport.js +3 -0
- package/dictionary/nodemailer.js +3 -0
- package/dictionary/npm-registry-client.js +7 -0
- package/dictionary/npm.js +7 -0
- package/dictionary/nssocket.js +3 -0
- package/dictionary/oauth2orize.js +7 -0
- package/dictionary/octobat.js +3 -0
- package/dictionary/open.js +13 -0
- package/dictionary/opn.js +4 -0
- package/dictionary/optimist.js +3 -0
- package/dictionary/passport-local.js +3 -0
- package/dictionary/passport.js +3 -0
- package/dictionary/pg-cursor.js +3 -0
- package/dictionary/pg-query-stream.js +3 -0
- package/dictionary/pg-types.js +7 -0
- package/dictionary/pg.js +7 -0
- package/dictionary/pg.js.js +7 -0
- package/dictionary/pgpass.js +7 -0
- package/dictionary/phantom.js +19 -0
- package/dictionary/phantomjs-prebuilt.js +16 -0
- package/dictionary/pkginfo.js +3 -0
- package/dictionary/pm2.js +7 -0
- package/dictionary/pmx.js +3 -0
- package/dictionary/pouchdb.js +3 -0
- package/dictionary/primus-emitter.js +3 -0
- package/dictionary/primus-spark-latency.js +3 -0
- package/dictionary/primus.js +3 -0
- package/dictionary/publicsuffixlist.js +15 -0
- package/dictionary/pug.js +3 -0
- package/dictionary/punt.js +3 -0
- package/dictionary/puppeteer.js +13 -0
- package/dictionary/pwd.js +3 -0
- package/dictionary/q.js +3 -0
- package/dictionary/raven.js +3 -0
- package/dictionary/rc.js +12 -0
- package/dictionary/readable-stream.js +3 -0
- package/dictionary/rechoir.js +3 -0
- package/dictionary/redis-parser.js +3 -0
- package/dictionary/redis.js +3 -0
- package/dictionary/regression.js +3 -0
- package/dictionary/reload.js +7 -0
- package/dictionary/request.js +3 -0
- package/dictionary/require-uncached.js +3 -0
- package/dictionary/require_optional.js +3 -0
- package/dictionary/s3.js +3 -0
- package/dictionary/safe_datejs.js +3 -0
- package/dictionary/sails.js +33 -0
- package/dictionary/sax.js +3 -0
- package/dictionary/scrypt.js +3 -0
- package/dictionary/semver.js +3 -0
- package/dictionary/sequelize.js +7 -0
- package/dictionary/serialport.js +3 -0
- package/dictionary/sha3.js +3 -0
- package/dictionary/sharp.js +11 -0
- package/dictionary/shelljs.js +7 -0
- package/dictionary/sinon.js +3 -0
- package/dictionary/socket.io-client.js +13 -0
- package/dictionary/socket.io.js +12 -0
- package/dictionary/sqip.js +7 -0
- package/dictionary/sqlite3.js +7 -0
- package/dictionary/steam-crypto.js +7 -0
- package/dictionary/steam-resources.js +19 -0
- package/dictionary/steam.js +3 -0
- package/dictionary/stripe-webhook-middleware.js +3 -0
- package/dictionary/stripe.js +3 -0
- package/dictionary/strong-globalize.js +3 -0
- package/dictionary/stylus.js +14 -0
- package/dictionary/supervisor.js +3 -0
- package/dictionary/svgo.js +8 -0
- package/dictionary/tabtab.js +3 -0
- package/dictionary/tesseract.js.js +7 -0
- package/dictionary/thread-stream.js +7 -0
- package/dictionary/throng.js +3 -0
- package/dictionary/time.js +3 -0
- package/dictionary/tinify.js +7 -0
- package/dictionary/tiny-worker.js +7 -0
- package/dictionary/tmp.js +3 -0
- package/dictionary/transformers.js +3 -0
- package/dictionary/uglify-js.js +9 -0
- package/dictionary/umd.js +19 -0
- package/dictionary/underscore.js +3 -0
- package/dictionary/union.js +3 -0
- package/dictionary/update-notifier.js +3 -0
- package/dictionary/usage.js +7 -0
- package/dictionary/v8flags.js +13 -0
- package/dictionary/verror.js +3 -0
- package/dictionary/voc.js +3 -0
- package/dictionary/webdriverio.js +7 -0
- package/dictionary/winston-uber.js +7 -0
- package/dictionary/winston.js +7 -0
- package/dictionary/ws.js +3 -0
- package/dictionary/xlsx.js +16 -0
- package/dictionary/xml2js.js +3 -0
- package/dictionary/yargs.js +3 -0
- package/dictionary/zeromq.js +13 -0
- package/lib-es5/addon-extract.js +164 -0
- package/lib-es5/analyzer.js +687 -0
- package/lib-es5/app-bundle.js +133 -0
- package/lib-es5/appdir.js +265 -0
- package/lib-es5/bin.js +304 -0
- package/lib-es5/bootstrap.js +179 -0
- package/lib-es5/bundler.js +496 -0
- package/lib-es5/chmod.js +15 -0
- package/lib-es5/colors.js +12 -0
- package/lib-es5/commands.js +376 -0
- package/lib-es5/common.js +328 -0
- package/lib-es5/compress_type.js +10 -0
- package/lib-es5/config.js +291 -0
- package/lib-es5/detector.js +421 -0
- package/lib-es5/esm-hooks.js +366 -0
- package/lib-es5/esm-resolver.js +292 -0
- package/lib-es5/esm-transformer.js +378 -0
- package/lib-es5/exports-resolver.js +184 -0
- package/lib-es5/external-artifacts.js +170 -0
- package/lib-es5/fabricator.js +137 -0
- package/lib-es5/follow.js +190 -0
- package/lib-es5/help.js +52 -0
- package/lib-es5/index.d.ts +2 -0
- package/lib-es5/index.js +552 -0
- package/lib-es5/log.js +7 -0
- package/lib-es5/mach-o.js +262 -0
- package/lib-es5/manifest.js +21 -0
- package/lib-es5/options.js +19 -0
- package/lib-es5/packager.js +1036 -0
- package/lib-es5/packer.js +137 -0
- package/lib-es5/pe-metadata.js +130 -0
- package/lib-es5/producer.js +378 -0
- package/lib-es5/refiner.js +87 -0
- package/lib-es5/resolver.js +142 -0
- package/lib-es5/runtime-diagnostics.js +172 -0
- package/lib-es5/sea.js +307 -0
- package/lib-es5/snapshot-fs-patch.js +396 -0
- package/lib-es5/snapshot-fs.js +255 -0
- package/lib-es5/snapshot-index.js +135 -0
- package/lib-es5/snapshot-path.js +168 -0
- package/lib-es5/types.js +9 -0
- package/lib-es5/walker.js +1019 -0
- package/lib-es5/windows-sign.js +139 -0
- package/package.json +99 -0
- package/prelude/bootstrap.js +2263 -0
- package/prelude/diagnostic.js +147 -0
|
@@ -0,0 +1,687 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Hakobu Project Analyzer
|
|
4
|
+
*
|
|
5
|
+
* Analyzes a Node.js project and produces a normalized PackagingManifest.
|
|
6
|
+
* This is the bridge between user config and the packaging pipeline.
|
|
7
|
+
*
|
|
8
|
+
* ESM-first: follows Node 24 semantics. .js format is determined by the
|
|
9
|
+
* nearest package.json "type" field. Packages with "exports" are flagged
|
|
10
|
+
* when the analyzer cannot fully resolve them.
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.analyze = void 0;
|
|
40
|
+
const fs_1 = __importDefault(require("fs"));
|
|
41
|
+
const path_1 = __importDefault(require("path"));
|
|
42
|
+
const babel = __importStar(require("@babel/parser"));
|
|
43
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
44
|
+
const exports_resolver_1 = require("./exports-resolver");
|
|
45
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
46
|
+
// Diagnostic helper
|
|
47
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
48
|
+
function diag(severity, category, message, file, suggestion) {
|
|
49
|
+
return { severity, category, message, file, suggestion };
|
|
50
|
+
}
|
|
51
|
+
const packageJsonCache = new Map();
|
|
52
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
53
|
+
// Package.json utilities
|
|
54
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
55
|
+
function findNearestPackageJson(fromDir) {
|
|
56
|
+
const root = path_1.default.parse(fromDir).root;
|
|
57
|
+
let dir = fromDir;
|
|
58
|
+
const visited = [];
|
|
59
|
+
while (dir !== root) {
|
|
60
|
+
if (packageJsonCache.has(dir)) {
|
|
61
|
+
const cached = packageJsonCache.get(dir);
|
|
62
|
+
for (const d of visited)
|
|
63
|
+
packageJsonCache.set(d, cached);
|
|
64
|
+
return cached;
|
|
65
|
+
}
|
|
66
|
+
visited.push(dir);
|
|
67
|
+
const pjPath = path_1.default.join(dir, 'package.json');
|
|
68
|
+
if (fs_1.default.existsSync(pjPath)) {
|
|
69
|
+
try {
|
|
70
|
+
const data = JSON.parse(fs_1.default.readFileSync(pjPath, 'utf8'));
|
|
71
|
+
const result = { path: pjPath, data };
|
|
72
|
+
for (const d of visited)
|
|
73
|
+
packageJsonCache.set(d, result);
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// Invalid JSON — keep walking
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
dir = path_1.default.dirname(dir);
|
|
81
|
+
}
|
|
82
|
+
for (const d of visited)
|
|
83
|
+
packageJsonCache.set(d, null);
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
function readPackageJson(pjPath) {
|
|
87
|
+
try {
|
|
88
|
+
return JSON.parse(fs_1.default.readFileSync(pjPath, 'utf8'));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
95
|
+
// Module format detection (Node 24 semantics)
|
|
96
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
97
|
+
function detectModuleFormat(filePath, explicitFormat) {
|
|
98
|
+
if (explicitFormat) {
|
|
99
|
+
return { format: explicitFormat, source: 'explicit' };
|
|
100
|
+
}
|
|
101
|
+
const ext = path_1.default.extname(filePath);
|
|
102
|
+
// Node 24 rule 1: .mjs → always ESM
|
|
103
|
+
if (ext === '.mjs')
|
|
104
|
+
return { format: 'esm', source: 'extension' };
|
|
105
|
+
// Node 24 rule 2: .cjs → always CJS
|
|
106
|
+
if (ext === '.cjs')
|
|
107
|
+
return { format: 'cjs', source: 'extension' };
|
|
108
|
+
// Node 24 rule 3: .js → check nearest package.json "type"
|
|
109
|
+
const pj = findNearestPackageJson(path_1.default.dirname(filePath));
|
|
110
|
+
if (pj?.data.type === 'module')
|
|
111
|
+
return { format: 'esm', source: 'package-type' };
|
|
112
|
+
// Default: CJS (Node's default when no "type" field)
|
|
113
|
+
return { format: 'cjs', source: 'package-type' };
|
|
114
|
+
}
|
|
115
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
116
|
+
// File classification
|
|
117
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
118
|
+
/**
|
|
119
|
+
* Recursively walk a directory and call the callback for each file.
|
|
120
|
+
*/
|
|
121
|
+
function walkDirRecursive(dir, cb) {
|
|
122
|
+
let entries;
|
|
123
|
+
try {
|
|
124
|
+
entries = fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
for (const entry of entries) {
|
|
130
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
131
|
+
if (entry.isDirectory()) {
|
|
132
|
+
walkDirRecursive(fullPath, cb);
|
|
133
|
+
}
|
|
134
|
+
else if (entry.isFile()) {
|
|
135
|
+
cb(fullPath);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function classifyFile(filePath) {
|
|
140
|
+
const ext = path_1.default.extname(filePath);
|
|
141
|
+
const base = path_1.default.basename(filePath);
|
|
142
|
+
if (base === 'package.json')
|
|
143
|
+
return 'package-json';
|
|
144
|
+
if (ext === '.node')
|
|
145
|
+
return 'native-addon';
|
|
146
|
+
if (ext === '.wasm')
|
|
147
|
+
return 'wasm';
|
|
148
|
+
if (ext === '.json')
|
|
149
|
+
return 'json';
|
|
150
|
+
if (['.js', '.mjs', '.cjs'].includes(ext))
|
|
151
|
+
return 'script';
|
|
152
|
+
return 'asset';
|
|
153
|
+
}
|
|
154
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
155
|
+
// Snapshot path computation
|
|
156
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
157
|
+
function toSnapshotPath(absolutePath, projectRoot, appId) {
|
|
158
|
+
const relative = path_1.default.relative(projectRoot, absolutePath);
|
|
159
|
+
const posix = relative.split(path_1.default.sep).join('/');
|
|
160
|
+
return `/snapshot/${appId}/${posix}`;
|
|
161
|
+
}
|
|
162
|
+
function extractDependencies(filePath, format) {
|
|
163
|
+
let source;
|
|
164
|
+
try {
|
|
165
|
+
source = fs_1.default.readFileSync(filePath, 'utf8');
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Try to extract a directory hint from a dynamic require argument.
|
|
172
|
+
* Recognizes patterns like:
|
|
173
|
+
* path.join(__dirname, 'models', variable) → 'models'
|
|
174
|
+
* __dirname + '/models/' + variable → 'models'
|
|
175
|
+
*/
|
|
176
|
+
function extractDirHint(node) {
|
|
177
|
+
// path.join(__dirname, 'subdir', ...)
|
|
178
|
+
if (node.type === 'CallExpression' &&
|
|
179
|
+
node.callee?.type === 'MemberExpression' &&
|
|
180
|
+
node.callee.property?.name === 'join' &&
|
|
181
|
+
node.arguments?.length >= 3) {
|
|
182
|
+
const args = node.arguments;
|
|
183
|
+
if (args[0]?.type === 'Identifier' && args[0].name === '__dirname' &&
|
|
184
|
+
args[1]?.type === 'StringLiteral') {
|
|
185
|
+
return args[1].value;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// __dirname + '/subdir/' + ... (BinaryExpression with string concat)
|
|
189
|
+
if (node.type === 'BinaryExpression' && node.operator === '+') {
|
|
190
|
+
const left = node.left;
|
|
191
|
+
if (left?.type === 'BinaryExpression' && left.operator === '+') {
|
|
192
|
+
if (left.left?.type === 'Identifier' && left.left.name === '__dirname' &&
|
|
193
|
+
left.right?.type === 'StringLiteral') {
|
|
194
|
+
const dir = left.right.value.replace(/^\/|\/$/g, '');
|
|
195
|
+
if (dir)
|
|
196
|
+
return dir;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
const deps = [];
|
|
203
|
+
try {
|
|
204
|
+
const ast = babel.parse(source, {
|
|
205
|
+
sourceType: format === 'esm' ? 'module' : 'script',
|
|
206
|
+
plugins: ['importMeta', 'dynamicImport'],
|
|
207
|
+
allowImportExportEverywhere: true,
|
|
208
|
+
allowReturnOutsideFunction: true,
|
|
209
|
+
errorRecovery: true,
|
|
210
|
+
});
|
|
211
|
+
(0, traverse_1.default)(ast, {
|
|
212
|
+
ImportDeclaration(p) {
|
|
213
|
+
deps.push({ specifier: p.node.source.value, dynamic: false, kind: 'import' });
|
|
214
|
+
},
|
|
215
|
+
CallExpression(p) {
|
|
216
|
+
const { callee, arguments: args } = p.node;
|
|
217
|
+
// require(...)
|
|
218
|
+
if (callee.type === 'Identifier' && callee.name === 'require' && args.length >= 1) {
|
|
219
|
+
if (args[0].type === 'StringLiteral') {
|
|
220
|
+
deps.push({ specifier: args[0].value, dynamic: false, kind: 'require' });
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Try to extract directory hint from path.join(__dirname, 'subdir', variable)
|
|
224
|
+
const dirHint = extractDirHint(args[0]);
|
|
225
|
+
deps.push({ specifier: '<dynamic>', dynamic: true, kind: 'require', dirHint });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// import(...)
|
|
229
|
+
if (callee.type === 'Import' && args.length >= 1) {
|
|
230
|
+
if (args[0].type === 'StringLiteral') {
|
|
231
|
+
deps.push({ specifier: args[0].value, dynamic: false, kind: 'import-dynamic' });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
deps.push({ specifier: '<dynamic>', dynamic: true, kind: 'import-dynamic' });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
ExportNamedDeclaration(p) {
|
|
239
|
+
if (p.node.source) {
|
|
240
|
+
deps.push({ specifier: p.node.source.value, dynamic: false, kind: 'export-from' });
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
ExportAllDeclaration(p) {
|
|
244
|
+
deps.push({ specifier: p.node.source.value, dynamic: false, kind: 'export-from' });
|
|
245
|
+
},
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
// Parse failure — return what we have
|
|
250
|
+
}
|
|
251
|
+
return deps;
|
|
252
|
+
}
|
|
253
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
254
|
+
// Module resolution (ESM-aware)
|
|
255
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
256
|
+
const builtinSet = new Set([
|
|
257
|
+
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster',
|
|
258
|
+
'console', 'constants', 'crypto', 'dgram', 'diagnostics_channel',
|
|
259
|
+
'dns', 'domain', 'events', 'fs', 'http', 'http2', 'https',
|
|
260
|
+
'inspector', 'module', 'net', 'os', 'path', 'perf_hooks',
|
|
261
|
+
'process', 'punycode', 'querystring', 'readline', 'repl',
|
|
262
|
+
'stream', 'string_decoder', 'sys', 'test', 'timers', 'tls',
|
|
263
|
+
'trace_events', 'tty', 'url', 'util', 'v8', 'vm', 'wasi',
|
|
264
|
+
'worker_threads', 'zlib', 'sqlite',
|
|
265
|
+
]);
|
|
266
|
+
function isBuiltin(specifier) {
|
|
267
|
+
return specifier.startsWith('node:') || builtinSet.has(specifier.split('/')[0]);
|
|
268
|
+
}
|
|
269
|
+
const RESOLVE_EXTENSIONS = ['.js', '.mjs', '.cjs', '.json', '.node'];
|
|
270
|
+
function resolveRelative(specifier, fromDir) {
|
|
271
|
+
const base = path_1.default.resolve(fromDir, specifier);
|
|
272
|
+
if (fs_1.default.existsSync(base) && fs_1.default.statSync(base).isFile())
|
|
273
|
+
return base;
|
|
274
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
275
|
+
const withExt = base + ext;
|
|
276
|
+
if (fs_1.default.existsSync(withExt) && fs_1.default.statSync(withExt).isFile())
|
|
277
|
+
return withExt;
|
|
278
|
+
}
|
|
279
|
+
if (fs_1.default.existsSync(base) && fs_1.default.statSync(base).isDirectory()) {
|
|
280
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
281
|
+
const indexFile = path_1.default.join(base, `index${ext}`);
|
|
282
|
+
if (fs_1.default.existsSync(indexFile))
|
|
283
|
+
return indexFile;
|
|
284
|
+
}
|
|
285
|
+
const dirPj = path_1.default.join(base, 'package.json');
|
|
286
|
+
if (fs_1.default.existsSync(dirPj)) {
|
|
287
|
+
const pj = readPackageJson(dirPj);
|
|
288
|
+
if (pj?.main) {
|
|
289
|
+
const mainPath = path_1.default.resolve(base, pj.main);
|
|
290
|
+
if (fs_1.default.existsSync(mainPath))
|
|
291
|
+
return mainPath;
|
|
292
|
+
for (const ext of RESOLVE_EXTENSIONS) {
|
|
293
|
+
if (fs_1.default.existsSync(mainPath + ext))
|
|
294
|
+
return mainPath + ext;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return null;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Resolve a bare package specifier. ESM-aware: when a package has an
|
|
303
|
+
* "exports" field, the analyzer flags that it used legacy fallback
|
|
304
|
+
* resolution, which may produce incorrect results for ESM-only exports.
|
|
305
|
+
*/
|
|
306
|
+
function resolvePackage(specifier, fromFile, warnings, conditions = exports_resolver_1.CJS_CONDITIONS) {
|
|
307
|
+
const pkgName = specifier.startsWith('@')
|
|
308
|
+
? specifier.split('/').slice(0, 2).join('/')
|
|
309
|
+
: specifier.split('/')[0];
|
|
310
|
+
const subpath = specifier.slice(pkgName.length) || '.';
|
|
311
|
+
let dir = path_1.default.dirname(fromFile);
|
|
312
|
+
const root = path_1.default.parse(dir).root;
|
|
313
|
+
while (dir !== root) {
|
|
314
|
+
const pkgDir = path_1.default.join(dir, 'node_modules', pkgName);
|
|
315
|
+
if (fs_1.default.existsSync(pkgDir)) {
|
|
316
|
+
const pkgJsonPath = path_1.default.join(pkgDir, 'package.json');
|
|
317
|
+
const pj = fs_1.default.existsSync(pkgJsonPath) ? readPackageJson(pkgJsonPath) : null;
|
|
318
|
+
const hasExports = pj?.exports != null;
|
|
319
|
+
// ── Exports map resolution ──
|
|
320
|
+
// When "exports" is present, Node uses ONLY the exports map.
|
|
321
|
+
// "main" is ignored for bare specifiers.
|
|
322
|
+
if (hasExports) {
|
|
323
|
+
const normalizedSubpath = '.' + specifier.slice(pkgName.length);
|
|
324
|
+
const exportsResult = (0, exports_resolver_1.resolveExports)(pj.exports, normalizedSubpath, conditions);
|
|
325
|
+
if (exportsResult && typeof exportsResult === 'string') {
|
|
326
|
+
const resolved = resolveRelative(exportsResult, pkgDir);
|
|
327
|
+
if (resolved)
|
|
328
|
+
return resolved;
|
|
329
|
+
}
|
|
330
|
+
// exports present but couldn't resolve — do NOT fall back to main/index
|
|
331
|
+
warnings.push(diag('warning', 'exports-not-resolved', `Could not resolve '${specifier}' via exports map in '${pkgName}'.`, fromFile, `Check that the exports map exposes this subpath.`));
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
// ── Legacy resolution (no exports) ──
|
|
335
|
+
if (subpath === '.') {
|
|
336
|
+
if (pj?.main) {
|
|
337
|
+
const resolved = resolveRelative(pj.main, pkgDir);
|
|
338
|
+
if (resolved)
|
|
339
|
+
return resolved;
|
|
340
|
+
}
|
|
341
|
+
const resolved = resolveRelative('./index', pkgDir);
|
|
342
|
+
if (resolved)
|
|
343
|
+
return resolved;
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
const resolved = resolveRelative(subpath, pkgDir);
|
|
347
|
+
if (resolved)
|
|
348
|
+
return resolved;
|
|
349
|
+
}
|
|
350
|
+
warnings.push(diag('warning', 'unresolved-import', `Could not resolve '${specifier}' within ${pkgDir}`, fromFile, 'Check that the package exports this path.'));
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
dir = path_1.default.dirname(dir);
|
|
354
|
+
}
|
|
355
|
+
warnings.push(diag('warning', 'unresolved-import', `Package '${pkgName}' not found in node_modules`, fromFile, `Run 'npm install' or 'pnpm install' to install dependencies.`));
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
function resolveSpecifier(specifier, fromFile, warnings, depKind = 'require') {
|
|
359
|
+
if (isBuiltin(specifier))
|
|
360
|
+
return null;
|
|
361
|
+
// Choose conditions based on caller context
|
|
362
|
+
const conditions = depKind === 'require' ? exports_resolver_1.CJS_CONDITIONS : exports_resolver_1.ESM_CONDITIONS;
|
|
363
|
+
// #-prefixed package imports
|
|
364
|
+
if (specifier.startsWith('#')) {
|
|
365
|
+
const pj = findNearestPackageJson(path_1.default.dirname(fromFile));
|
|
366
|
+
if (pj?.data.imports) {
|
|
367
|
+
const resolved = (0, exports_resolver_1.resolveImports)(pj.data.imports, specifier, conditions);
|
|
368
|
+
if (resolved && typeof resolved === 'string') {
|
|
369
|
+
const pkgDir = path_1.default.dirname(pj.path);
|
|
370
|
+
return resolveRelative(resolved, pkgDir);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
warnings.push(diag('warning', 'imports-not-resolved', `Could not resolve '${specifier}' via imports map.`, fromFile, `Check that the nearest package.json has an "imports" entry for '${specifier}'.`));
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
if (specifier.startsWith('.') || specifier.startsWith('/')) {
|
|
377
|
+
return resolveRelative(specifier, path_1.default.dirname(fromFile));
|
|
378
|
+
}
|
|
379
|
+
return resolvePackage(specifier, fromFile, warnings, conditions);
|
|
380
|
+
}
|
|
381
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
382
|
+
// Package boundary detection
|
|
383
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
384
|
+
function findPackageBoundary(filePath, projectRoot) {
|
|
385
|
+
const pj = findNearestPackageJson(path_1.default.dirname(filePath));
|
|
386
|
+
if (!pj)
|
|
387
|
+
return null;
|
|
388
|
+
if (!pj.path.startsWith(projectRoot))
|
|
389
|
+
return null;
|
|
390
|
+
return pj.path;
|
|
391
|
+
}
|
|
392
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
393
|
+
// Main analyzer
|
|
394
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
395
|
+
async function analyze(options) {
|
|
396
|
+
const projectRoot = fs_1.default.realpathSync(options.projectRoot);
|
|
397
|
+
const warnings = [];
|
|
398
|
+
packageJsonCache.clear();
|
|
399
|
+
// ── 1. Resolve project package.json ──
|
|
400
|
+
const rootPjPath = path_1.default.join(projectRoot, 'package.json');
|
|
401
|
+
const rootPj = fs_1.default.existsSync(rootPjPath) ? readPackageJson(rootPjPath) : null;
|
|
402
|
+
const appId = rootPj?.name?.replace(/^@[^/]+\//, '') || path_1.default.basename(projectRoot);
|
|
403
|
+
// ── Legacy pkg config diagnostic ──
|
|
404
|
+
if (rootPj?.pkg) {
|
|
405
|
+
warnings.push(diag('info', 'legacy-pkg-config', `package.json contains a "pkg" configuration section. ` +
|
|
406
|
+
`Hakobu does not yet read legacy pkg config fields (scripts, assets).`, rootPjPath, `Migrate to Hakobu config format or use --assets / --entry CLI flags. ` +
|
|
407
|
+
`Legacy "pkg.scripts" and "pkg.assets" globs will be supported in a future release.`));
|
|
408
|
+
}
|
|
409
|
+
// ── Root-level imports map diagnostic ──
|
|
410
|
+
if (rootPj?.imports) {
|
|
411
|
+
warnings.push(diag('warning', 'imports-not-resolved', `Project package.json uses "imports" (subpath imports). ` +
|
|
412
|
+
`#-prefixed specifiers in your code may not resolve correctly in the packaged app.`, rootPjPath, `Subpath imports resolution will be implemented before native ESM support is complete.`));
|
|
413
|
+
}
|
|
414
|
+
// ── 2. Resolve entrypoint ──
|
|
415
|
+
let entryPath;
|
|
416
|
+
if (options.entry) {
|
|
417
|
+
entryPath = path_1.default.isAbsolute(options.entry)
|
|
418
|
+
? options.entry
|
|
419
|
+
: path_1.default.resolve(projectRoot, options.entry);
|
|
420
|
+
}
|
|
421
|
+
else if (rootPj?.exports) {
|
|
422
|
+
// If the project has "exports", use it to find the entry
|
|
423
|
+
// For now, only handle the simple case: exports = "./file.js" or exports.".".default
|
|
424
|
+
const entryFromExports = resolveExportsEntry(rootPj.exports, projectRoot);
|
|
425
|
+
if (entryFromExports) {
|
|
426
|
+
entryPath = entryFromExports;
|
|
427
|
+
}
|
|
428
|
+
else if (rootPj?.main) {
|
|
429
|
+
entryPath = path_1.default.resolve(projectRoot, rootPj.main);
|
|
430
|
+
warnings.push(diag('warning', 'exports-not-resolved', `Project has an "exports" field but Hakobu could not extract the entry from it. ` +
|
|
431
|
+
`Falling back to "main": "${rootPj.main}".`, rootPjPath, `For complex exports maps, specify the entry explicitly with --entry.`));
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
entryPath = path_1.default.resolve(projectRoot, 'index.js');
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
else if (rootPj?.main) {
|
|
438
|
+
entryPath = path_1.default.resolve(projectRoot, rootPj.main);
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
entryPath = path_1.default.resolve(projectRoot, 'index.js');
|
|
442
|
+
}
|
|
443
|
+
if (!fs_1.default.existsSync(entryPath)) {
|
|
444
|
+
throw new Error(`Entrypoint not found: ${entryPath}\n` +
|
|
445
|
+
`Specify an entry via --entry or set "main" in package.json.`);
|
|
446
|
+
}
|
|
447
|
+
entryPath = fs_1.default.realpathSync(entryPath);
|
|
448
|
+
const { format: entryFormat, source: entryFormatSource } = detectModuleFormat(entryPath, options.format);
|
|
449
|
+
const entry = {
|
|
450
|
+
absolutePath: entryPath,
|
|
451
|
+
snapshotPath: toSnapshotPath(entryPath, projectRoot, appId),
|
|
452
|
+
format: entryFormat,
|
|
453
|
+
formatSource: entryFormatSource,
|
|
454
|
+
};
|
|
455
|
+
// ── 3. Walk dependency graph ──
|
|
456
|
+
const files = {};
|
|
457
|
+
const packagesMap = {};
|
|
458
|
+
const nativeAddons = [];
|
|
459
|
+
const visited = new Set();
|
|
460
|
+
function addFile(absolutePath, kindOverride) {
|
|
461
|
+
const realPath = fs_1.default.realpathSync(absolutePath);
|
|
462
|
+
if (visited.has(realPath))
|
|
463
|
+
return null;
|
|
464
|
+
visited.add(realPath);
|
|
465
|
+
if (!realPath.startsWith(projectRoot)) {
|
|
466
|
+
warnings.push(diag('warning', 'unsupported-feature', `File outside project root: ${realPath}`, realPath, 'Ensure all dependencies are installed within the project.'));
|
|
467
|
+
return null;
|
|
468
|
+
}
|
|
469
|
+
const snapshotPath = toSnapshotPath(realPath, projectRoot, appId);
|
|
470
|
+
const kind = kindOverride || classifyFile(realPath);
|
|
471
|
+
const pjBoundary = findPackageBoundary(realPath, projectRoot);
|
|
472
|
+
const boundarySnapshot = pjBoundary ? toSnapshotPath(pjBoundary, projectRoot, appId) : null;
|
|
473
|
+
let format = null;
|
|
474
|
+
if (kind === 'script') {
|
|
475
|
+
format = detectModuleFormat(realPath).format;
|
|
476
|
+
}
|
|
477
|
+
const file = {
|
|
478
|
+
absolutePath: realPath,
|
|
479
|
+
snapshotPath,
|
|
480
|
+
kind,
|
|
481
|
+
format,
|
|
482
|
+
packageBoundary: boundarySnapshot,
|
|
483
|
+
};
|
|
484
|
+
files[snapshotPath] = file;
|
|
485
|
+
if (kind === 'package-json') {
|
|
486
|
+
const pjData = readPackageJson(realPath);
|
|
487
|
+
if (pjData) {
|
|
488
|
+
packagesMap[snapshotPath] = {
|
|
489
|
+
snapshotPath,
|
|
490
|
+
name: pjData.name ?? null,
|
|
491
|
+
version: pjData.version ?? null,
|
|
492
|
+
type: (pjData.type === 'module' ? 'module' : pjData.type === 'commonjs' ? 'commonjs' : null),
|
|
493
|
+
main: pjData.main ?? null,
|
|
494
|
+
exports: pjData.exports ?? null,
|
|
495
|
+
imports: pjData.imports ?? null,
|
|
496
|
+
dependencies: pjData.dependencies ?? null,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
if (kind === 'native-addon') {
|
|
501
|
+
// Compute content hash for deterministic extraction path
|
|
502
|
+
const addonContent = fs_1.default.readFileSync(realPath);
|
|
503
|
+
const addonHash = require('crypto')
|
|
504
|
+
.createHash('sha256')
|
|
505
|
+
.update(addonContent)
|
|
506
|
+
.digest('hex');
|
|
507
|
+
nativeAddons.push({
|
|
508
|
+
snapshotPath,
|
|
509
|
+
absolutePath: realPath,
|
|
510
|
+
contentHash: addonHash,
|
|
511
|
+
targetPlatform: null,
|
|
512
|
+
targetArch: null,
|
|
513
|
+
});
|
|
514
|
+
// Auto-include all files in the native addon's package directory.
|
|
515
|
+
// Native packages (sharp, drivelist, etc.) often read sibling files
|
|
516
|
+
// (vendor configs, data files) via fs.readFileSync() at runtime.
|
|
517
|
+
// The prelude's dlopen patch copies the entire package directory to
|
|
518
|
+
// the extraction cache, so we must ensure all files are in the snapshot.
|
|
519
|
+
const addonDir = path_1.default.dirname(realPath);
|
|
520
|
+
const addonParts = addonDir.split(path_1.default.sep);
|
|
521
|
+
const nmIndex = addonParts.lastIndexOf('node_modules');
|
|
522
|
+
if (nmIndex >= 0 && nmIndex + 1 < addonParts.length) {
|
|
523
|
+
// Determine package root: node_modules/@scope/pkg or node_modules/pkg
|
|
524
|
+
let pkgRootIdx = nmIndex + 1;
|
|
525
|
+
if (addonParts[pkgRootIdx]?.startsWith('@') && pkgRootIdx + 1 < addonParts.length) {
|
|
526
|
+
pkgRootIdx += 1; // scoped package
|
|
527
|
+
}
|
|
528
|
+
const pkgRoot = addonParts.slice(0, pkgRootIdx + 1).join(path_1.default.sep);
|
|
529
|
+
if (fs_1.default.existsSync(pkgRoot)) {
|
|
530
|
+
walkDirRecursive(pkgRoot, (filePath) => {
|
|
531
|
+
if (!visited.has(filePath)) {
|
|
532
|
+
addFile(filePath);
|
|
533
|
+
}
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return file;
|
|
539
|
+
}
|
|
540
|
+
function walkFile(absolutePath) {
|
|
541
|
+
const file = addFile(absolutePath);
|
|
542
|
+
if (!file)
|
|
543
|
+
return;
|
|
544
|
+
if (file.kind !== 'script')
|
|
545
|
+
return;
|
|
546
|
+
const pjBoundary = findPackageBoundary(absolutePath, projectRoot);
|
|
547
|
+
if (pjBoundary && !visited.has(fs_1.default.realpathSync(pjBoundary))) {
|
|
548
|
+
addFile(pjBoundary);
|
|
549
|
+
}
|
|
550
|
+
const deps = extractDependencies(absolutePath, file.format);
|
|
551
|
+
for (const dep of deps) {
|
|
552
|
+
// ── Dynamic specifier diagnostics ──
|
|
553
|
+
if (dep.dynamic) {
|
|
554
|
+
const category = dep.kind === 'require' ? 'dynamic-require' : 'dynamic-import';
|
|
555
|
+
let suggestion;
|
|
556
|
+
if (dep.dirHint && dep.kind === 'require') {
|
|
557
|
+
suggestion = `Detected directory pattern: "${dep.dirHint}". ` +
|
|
558
|
+
`Add to hakobu config: { "assets": ["${dep.dirHint}/**/*.js"] }`;
|
|
559
|
+
}
|
|
560
|
+
else if (dep.kind === 'require') {
|
|
561
|
+
suggestion = `If the required module is known, add it to the assets list explicitly. ` +
|
|
562
|
+
`Example: { "hakobu": { "assets": ["path/to/module.js"] } }`;
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
suggestion = `If the imported module is known, add it as a static import or to the assets list.`;
|
|
566
|
+
}
|
|
567
|
+
warnings.push(diag('warning', category, `${dep.kind}() with non-literal argument in ${path_1.default.basename(absolutePath)}. ` +
|
|
568
|
+
`Hakobu cannot trace dynamic ${dep.kind === 'require' ? 'require' : 'import'} targets statically.`, absolutePath, suggestion));
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
const resolved = resolveSpecifier(dep.specifier, absolutePath, warnings, dep.kind);
|
|
572
|
+
if (resolved) {
|
|
573
|
+
walkFile(resolved);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
walkFile(entryPath);
|
|
578
|
+
if (rootPj && fs_1.default.existsSync(rootPjPath)) {
|
|
579
|
+
addFile(rootPjPath);
|
|
580
|
+
}
|
|
581
|
+
// ── 4. Resolve asset globs ──
|
|
582
|
+
if (options.assets && options.assets.length > 0) {
|
|
583
|
+
for (const pattern of options.assets) {
|
|
584
|
+
const assetPath = path_1.default.resolve(projectRoot, pattern);
|
|
585
|
+
if (fs_1.default.existsSync(assetPath) && fs_1.default.statSync(assetPath).isFile()) {
|
|
586
|
+
// Direct file path
|
|
587
|
+
addFile(assetPath, 'asset');
|
|
588
|
+
}
|
|
589
|
+
else {
|
|
590
|
+
// Try as glob using tinyglobby.
|
|
591
|
+
// When the pattern or cwd contains glob-special characters
|
|
592
|
+
// (brackets, parens, etc.), we resolve the directory prefix
|
|
593
|
+
// first and glob from within it to avoid misinterpretation.
|
|
594
|
+
try {
|
|
595
|
+
const { globSync } = require('tinyglobby');
|
|
596
|
+
// Extract the directory prefix from the pattern (e.g., "models/**" → "models")
|
|
597
|
+
const firstWild = pattern.search(/[*?{]/);
|
|
598
|
+
let globCwd = projectRoot;
|
|
599
|
+
let globPattern = pattern;
|
|
600
|
+
if (firstWild > 0) {
|
|
601
|
+
const prefix = pattern.slice(0, firstWild);
|
|
602
|
+
const lastSep = prefix.lastIndexOf('/');
|
|
603
|
+
if (lastSep >= 0) {
|
|
604
|
+
const dirPrefix = prefix.slice(0, lastSep);
|
|
605
|
+
const resolvedDir = path_1.default.resolve(projectRoot, dirPrefix);
|
|
606
|
+
if (fs_1.default.existsSync(resolvedDir) && fs_1.default.statSync(resolvedDir).isDirectory()) {
|
|
607
|
+
globCwd = resolvedDir;
|
|
608
|
+
globPattern = pattern.slice(lastSep + 1);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
const matches = globSync(globPattern, { cwd: globCwd, absolute: true });
|
|
613
|
+
for (const match of matches) {
|
|
614
|
+
try {
|
|
615
|
+
if (fs_1.default.statSync(match).isFile()) {
|
|
616
|
+
addFile(match, 'asset');
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
catch { }
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
catch { }
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
// ── 5. Build externals ──
|
|
627
|
+
const externals = (options.externals ?? []).map((pattern) => ({
|
|
628
|
+
name: pattern,
|
|
629
|
+
pattern,
|
|
630
|
+
required: false,
|
|
631
|
+
}));
|
|
632
|
+
// ── 6. Assemble manifest ──
|
|
633
|
+
return {
|
|
634
|
+
projectRoot,
|
|
635
|
+
appId,
|
|
636
|
+
entry,
|
|
637
|
+
files,
|
|
638
|
+
packages: packagesMap,
|
|
639
|
+
nativeAddons,
|
|
640
|
+
externals,
|
|
641
|
+
targets: options.targets ?? [],
|
|
642
|
+
bundleMode: null,
|
|
643
|
+
compression: options.compression ?? 'none',
|
|
644
|
+
runtimeFlags: options.runtimeFlags ?? [],
|
|
645
|
+
warnings,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
exports.analyze = analyze;
|
|
649
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
650
|
+
// Helpers
|
|
651
|
+
// ─────────────────────────────────────────────────────────────────────
|
|
652
|
+
/**
|
|
653
|
+
* Try to extract a single entry file from a package.json "exports" field.
|
|
654
|
+
* Handles the simplest common cases only:
|
|
655
|
+
* exports: "./file.js"
|
|
656
|
+
* exports: { ".": "./file.js" }
|
|
657
|
+
* exports: { ".": { "default": "./file.js" } }
|
|
658
|
+
* exports: { ".": { "import": "./file.js" } }
|
|
659
|
+
*/
|
|
660
|
+
function resolveExportsEntry(exports, projectRoot) {
|
|
661
|
+
if (typeof exports === 'string') {
|
|
662
|
+
const resolved = path_1.default.resolve(projectRoot, exports);
|
|
663
|
+
return fs_1.default.existsSync(resolved) ? resolved : null;
|
|
664
|
+
}
|
|
665
|
+
if (typeof exports === 'object' && exports !== null && !Array.isArray(exports)) {
|
|
666
|
+
const map = exports;
|
|
667
|
+
// { ".": ... }
|
|
668
|
+
const dotEntry = map['.'];
|
|
669
|
+
if (typeof dotEntry === 'string') {
|
|
670
|
+
const resolved = path_1.default.resolve(projectRoot, dotEntry);
|
|
671
|
+
return fs_1.default.existsSync(resolved) ? resolved : null;
|
|
672
|
+
}
|
|
673
|
+
// { ".": { "import": "...", "default": "..." } }
|
|
674
|
+
if (typeof dotEntry === 'object' && dotEntry !== null) {
|
|
675
|
+
const conditions = dotEntry;
|
|
676
|
+
for (const key of ['import', 'require', 'node', 'default']) {
|
|
677
|
+
if (typeof conditions[key] === 'string') {
|
|
678
|
+
const resolved = path_1.default.resolve(projectRoot, conditions[key]);
|
|
679
|
+
if (fs_1.default.existsSync(resolved))
|
|
680
|
+
return resolved;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return null;
|
|
686
|
+
}
|
|
687
|
+
//# sourceMappingURL=analyzer.js.map
|