ts-arc 1.1.22 → 1.1.24

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/dist/bin.js CHANGED
@@ -83,7 +83,9 @@ function findTsConfig(dir) {
83
83
  var tsArcConfig = {
84
84
  baseUrl: null,
85
85
  paths: {},
86
- tsconfigDir: null
86
+ tsconfigDir: null,
87
+ emitDecoratorMetadata: false,
88
+ experimentalDecorators: false
87
89
  };
88
90
  var tsconfigPath = findTsConfig(process.cwd());
89
91
  if (tsconfigPath) {
@@ -94,6 +96,8 @@ if (tsconfigPath) {
94
96
  tsArcConfig.baseUrl = baseUrlStr ? path.resolve(tsconfigDir, baseUrlStr) : null;
95
97
  tsArcConfig.paths = compilerOptions.paths || {};
96
98
  tsArcConfig.tsconfigDir = tsconfigDir;
99
+ tsArcConfig.emitDecoratorMetadata = compilerOptions.emitDecoratorMetadata || false;
100
+ tsArcConfig.experimentalDecorators = compilerOptions.experimentalDecorators || false;
97
101
  }
98
102
  function registerLoader() {
99
103
  register(loaderPath, import.meta.url, { data: tsArcConfig });
@@ -108,6 +112,8 @@ async function setArcTsConfig(directory) {
108
112
  tsArcConfig.baseUrl = baseUrlStr ? path.resolve(tsconfigDir, baseUrlStr) : null;
109
113
  tsArcConfig.paths = compilerOptions.paths || {};
110
114
  tsArcConfig.tsconfigDir = tsconfigDir;
115
+ tsArcConfig.emitDecoratorMetadata = compilerOptions.emitDecoratorMetadata || false;
116
+ tsArcConfig.experimentalDecorators = compilerOptions.experimentalDecorators || false;
111
117
  }
112
118
  }
113
119
  async function loadModule(scriptUrl) {
package/dist/cli.js CHANGED
@@ -89,7 +89,9 @@ function findTsConfig(dir) {
89
89
  var tsArcConfig = {
90
90
  baseUrl: null,
91
91
  paths: {},
92
- tsconfigDir: null
92
+ tsconfigDir: null,
93
+ emitDecoratorMetadata: false,
94
+ experimentalDecorators: false
93
95
  };
94
96
  var tsconfigPath = findTsConfig(process.cwd());
95
97
  if (tsconfigPath) {
@@ -100,6 +102,8 @@ if (tsconfigPath) {
100
102
  tsArcConfig.baseUrl = baseUrlStr ? path.resolve(tsconfigDir, baseUrlStr) : null;
101
103
  tsArcConfig.paths = compilerOptions.paths || {};
102
104
  tsArcConfig.tsconfigDir = tsconfigDir;
105
+ tsArcConfig.emitDecoratorMetadata = compilerOptions.emitDecoratorMetadata || false;
106
+ tsArcConfig.experimentalDecorators = compilerOptions.experimentalDecorators || false;
103
107
  }
104
108
  function registerLoader() {
105
109
  register(loaderPath, import.meta.url, { data: tsArcConfig });
@@ -114,6 +118,8 @@ async function setArcTsConfig(directory) {
114
118
  tsArcConfig.baseUrl = baseUrlStr ? path.resolve(tsconfigDir, baseUrlStr) : null;
115
119
  tsArcConfig.paths = compilerOptions.paths || {};
116
120
  tsArcConfig.tsconfigDir = tsconfigDir;
121
+ tsArcConfig.emitDecoratorMetadata = compilerOptions.emitDecoratorMetadata || false;
122
+ tsArcConfig.experimentalDecorators = compilerOptions.experimentalDecorators || false;
117
123
  }
118
124
  }
119
125
  async function loadModule(scriptUrl2) {
package/dist/loader.js CHANGED
@@ -5,12 +5,15 @@ import * as fs from "fs";
5
5
  import * as path from "path";
6
6
  import * as url from "url";
7
7
  import { createRequire } from "module";
8
+ import { builtinModules } from "node:module";
8
9
  var require2 = createRequire(import.meta.url);
9
10
  var { transformSync } = require2("esbuild");
10
11
  var config = {
11
12
  baseUrl: null,
12
13
  paths: {},
13
- tsconfigDir: null
14
+ tsconfigDir: null,
15
+ emitDecoratorMetadata: false,
16
+ experimentalDecorators: false
14
17
  };
15
18
  function initialize(initContext) {
16
19
  config = initContext;
@@ -43,6 +46,179 @@ function resolveLocalSync(baseDir, relativePath) {
43
46
  async function resolveLocal(baseDir, relativePath) {
44
47
  return resolveLocalSync(baseDir, relativePath);
45
48
  }
49
+ function resolveBareSync(specifier, parentPath) {
50
+ const requireFromParent = createRequire(path.join(parentPath, "index.js"));
51
+ try {
52
+ const resolved = requireFromParent.resolve(specifier);
53
+ if (resolved === specifier && builtinModules.includes(specifier.replace(/^node:/, ""))) {
54
+ return `node:${specifier.replace(/^node:/, "")}`;
55
+ }
56
+ return url.pathToFileURL(resolved).href;
57
+ } catch (e) {
58
+ if (e.code === "MODULE_NOT_FOUND") {
59
+ throw Object.assign(new Error(`Cannot find module '${specifier}'`), { code: "ERR_MODULE_NOT_FOUND" });
60
+ }
61
+ throw e;
62
+ }
63
+ }
64
+ function getFormatSync(urlStr) {
65
+ const urlObj = new URL(urlStr);
66
+ if (urlObj.protocol === "node:") return "builtin";
67
+ if (urlObj.protocol !== "file:") throw new Error(`Unsupported protocol: ${urlObj.protocol}`);
68
+ const filePath = url.fileURLToPath(urlStr);
69
+ const ext = path.extname(filePath).toLowerCase();
70
+ if (ext === ".wasm") return "wasm";
71
+ if (ext === ".json") return "json";
72
+ if (ext === ".node") return "addon";
73
+ if (ext === ".mjs") return "module";
74
+ if (ext === ".cjs") return "commonjs";
75
+ if (ext !== ".js") throw new Error(`Unknown file extension: ${ext}`);
76
+ let currentDir = path.dirname(filePath);
77
+ while (currentDir !== path.parse(currentDir).root) {
78
+ const pkgPath = path.join(currentDir, "package.json");
79
+ if (fs.existsSync(pkgPath)) {
80
+ const pkgContent = fs.readFileSync(pkgPath, "utf8");
81
+ const pkg = JSON.parse(pkgContent);
82
+ if (pkg.type === "module") return "module";
83
+ return "commonjs";
84
+ }
85
+ currentDir = path.dirname(currentDir);
86
+ }
87
+ return "commonjs";
88
+ }
89
+ function getRuntimeType(typeStr) {
90
+ typeStr = typeStr.replace(/\s+/g, "");
91
+ if (typeStr.includes("|") || typeStr.includes("&") || typeStr === "any" || typeStr === "unknown" || typeStr === "never") {
92
+ return "Object";
93
+ }
94
+ if (typeStr === "void") {
95
+ return "undefined";
96
+ }
97
+ if (typeStr.endsWith("[]")) {
98
+ return 'typeof Array === "undefined" ? Object : Array';
99
+ }
100
+ const genericMatch = typeStr.match(/^(\w+)<.*>$/);
101
+ if (genericMatch) {
102
+ const base = genericMatch[1];
103
+ return `typeof ${base} === "undefined" ? Object : ${base}`;
104
+ }
105
+ const mapped = {
106
+ "string": "String",
107
+ "number": "Number",
108
+ "boolean": "Boolean",
109
+ "bigint": "BigInt",
110
+ "symbol": "Symbol",
111
+ "undefined": "undefined",
112
+ "object": "Object",
113
+ "function": "Function"
114
+ };
115
+ const lower = typeStr.toLowerCase();
116
+ if (mapped[lower]) {
117
+ const val = mapped[lower];
118
+ if (val !== "undefined") {
119
+ return `typeof ${val} === "undefined" ? Object : ${val}`;
120
+ }
121
+ return val;
122
+ }
123
+ return `typeof ${typeStr} === "undefined" ? Object : ${typeStr}`;
124
+ }
125
+ function addMetadataDecorators(code) {
126
+ const lines = code.split("\n");
127
+ const newLines = [...lines];
128
+ const insertions = [];
129
+ let inClass = false;
130
+ let classDecoratorEnd = -1;
131
+ let classIndent = "";
132
+ let constructorParamTypes = [];
133
+ let currentDecorators = [];
134
+ for (let i = 0; i < lines.length; i++) {
135
+ const line = lines[i];
136
+ const trimLine = line.trim();
137
+ if (trimLine.startsWith("@")) {
138
+ currentDecorators.push(i);
139
+ continue;
140
+ }
141
+ if (trimLine.startsWith("class ") || trimLine.startsWith("export class ")) {
142
+ inClass = true;
143
+ constructorParamTypes = [];
144
+ classIndent = line.match(/^\s*/)?.[0] || "";
145
+ classDecoratorEnd = currentDecorators.length > 0 ? currentDecorators[currentDecorators.length - 1] + 1 : i;
146
+ currentDecorators = [];
147
+ continue;
148
+ }
149
+ if (inClass && trimLine.startsWith("}")) {
150
+ const metas = [];
151
+ if (constructorParamTypes.length > 0 || true) {
152
+ metas.push(`${classIndent}@__metadata("design:paramtypes", [${constructorParamTypes.join(", ")}])`);
153
+ }
154
+ if (metas.length > 0) {
155
+ insertions.push({ line: classDecoratorEnd, content: metas });
156
+ }
157
+ inClass = false;
158
+ currentDecorators = [];
159
+ continue;
160
+ }
161
+ if (inClass) {
162
+ const propMatch = trimLine.match(/^((?:public|private|protected|static|readonly)\s+)*(\w+)\s*:\s*([^;]+);$/);
163
+ if (propMatch && !trimLine.includes("(")) {
164
+ const typeStr = propMatch[3];
165
+ const runtimeType = getRuntimeType(typeStr);
166
+ const indent = line.match(/^\s*/)?.[0] || "";
167
+ const metadataLine = `${indent}@__metadata("design:type", ${runtimeType})`;
168
+ const insertLine = currentDecorators.length > 0 ? currentDecorators[currentDecorators.length - 1] + 1 : i;
169
+ insertions.push({ line: insertLine, content: [metadataLine] });
170
+ currentDecorators = [];
171
+ continue;
172
+ }
173
+ const methodMatch = trimLine.match(/^((?:public|private|protected|static|async)\s+)*(\w+)\s*\(([^)]*)\)\s*:\s*([^ {;]+)(;| \{)?$/);
174
+ if (methodMatch) {
175
+ const paramsStr = methodMatch[3];
176
+ const returnStr = methodMatch[4];
177
+ const paramTypes = [];
178
+ if (paramsStr) {
179
+ const params = paramsStr.split(",");
180
+ params.forEach((p) => {
181
+ const ptMatch = p.trim().match(/:\s*([^,]+)/);
182
+ const pt = ptMatch ? ptMatch[1].trim() : "Object";
183
+ paramTypes.push(getRuntimeType(pt));
184
+ });
185
+ }
186
+ const runtimeReturn = getRuntimeType(returnStr);
187
+ const indent = line.match(/^\s*/)?.[0] || "";
188
+ const metas = [
189
+ `${indent}@__metadata("design:type", Function)`,
190
+ `${indent}@__metadata("design:paramtypes", [${paramTypes.join(", ")}])`,
191
+ `${indent}@__metadata("design:returntype", ${runtimeReturn})`
192
+ ];
193
+ const insertLine = currentDecorators.length > 0 ? currentDecorators[currentDecorators.length - 1] + 1 : i;
194
+ insertions.push({ line: insertLine, content: metas });
195
+ currentDecorators = [];
196
+ continue;
197
+ }
198
+ const ctorMatch = trimLine.match(/^(?:(public|private|protected)\s+)?constructor\s*\(\s*(.*)\s*\)/);
199
+ if (ctorMatch) {
200
+ const paramsStr = ctorMatch[2];
201
+ constructorParamTypes = [];
202
+ if (paramsStr) {
203
+ const params = paramsStr.split(",");
204
+ params.forEach((p) => {
205
+ const paramMatch = p.trim().match(/^.*?:\s*([^,]+)/);
206
+ const paramType = paramMatch ? paramMatch[1].trim() : "Object";
207
+ constructorParamTypes.push(getRuntimeType(paramType));
208
+ });
209
+ }
210
+ currentDecorators = [];
211
+ continue;
212
+ }
213
+ }
214
+ currentDecorators = [];
215
+ }
216
+ insertions.sort((a, b) => b.line - a.line);
217
+ for (const ins of insertions) {
218
+ newLines.splice(ins.line, 0, ...ins.content);
219
+ }
220
+ return newLines.join("\n");
221
+ }
46
222
  async function resolve2(specifier, context, nextResolve) {
47
223
  let parentPath = process.cwd();
48
224
  if (context.parentURL) {
@@ -52,8 +228,7 @@ async function resolve2(specifier, context, nextResolve) {
52
228
  const filePath = url.fileURLToPath(specifier);
53
229
  const dir = path.dirname(filePath);
54
230
  const baseName = path.basename(filePath);
55
- const relative = path.extname(baseName) ? baseName : baseName;
56
- const resolved = await resolveLocal(dir, relative);
231
+ const resolved = await resolveLocal(dir, baseName);
57
232
  return { ...resolved, shortCircuit: true };
58
233
  }
59
234
  const isPathLike = specifier.startsWith(".") || specifier.startsWith("/");
@@ -77,8 +252,8 @@ async function resolve2(specifier, context, nextResolve) {
77
252
  const mapped = isWildcard ? target.replace(/\*/g, capture) : target;
78
253
  if (effectiveBase) {
79
254
  try {
80
- const resolved2 = await resolveLocal(effectiveBase, mapped);
81
- return { ...resolved2, shortCircuit: true };
255
+ const resolved = await resolveLocal(effectiveBase, mapped);
256
+ return { ...resolved, shortCircuit: true };
82
257
  } catch (error) {
83
258
  if (error.code !== "ERR_MODULE_NOT_FOUND") {
84
259
  throw error;
@@ -90,63 +265,70 @@ async function resolve2(specifier, context, nextResolve) {
90
265
  }
91
266
  if (effectiveBase) {
92
267
  try {
93
- const resolved2 = await resolveLocal(effectiveBase, specifier);
94
- return { ...resolved2, shortCircuit: true };
268
+ const resolved = await resolveLocal(effectiveBase, specifier);
269
+ return { ...resolved, shortCircuit: true };
95
270
  } catch (error) {
96
271
  if (error.code !== "ERR_MODULE_NOT_FOUND") {
97
272
  throw error;
98
273
  }
99
274
  }
100
275
  }
101
- const resolved = await nextResolve(specifier, context);
102
- return { ...resolved, shortCircuit: true };
276
+ const resolvedUrl = resolveBareSync(specifier, parentPath);
277
+ return { url: resolvedUrl, shortCircuit: true };
103
278
  }
104
279
  }
105
280
  async function load(urlStr, context, nextLoad) {
106
- if (!urlStr.endsWith(".ts") && !urlStr.endsWith(".tsx")) {
107
- return nextLoad(urlStr, context);
108
- }
109
- const esbuildLoader = urlStr.endsWith(".tsx") ? "tsx" : "ts";
110
- const filePath = url.fileURLToPath(urlStr);
111
- const rawSource = fs.readFileSync(filePath, "utf8");
112
- const { code } = transformSync(rawSource, {
113
- loader: esbuildLoader,
114
- format: "esm",
115
- target: `node${process.versions.node}`,
116
- sourcemap: "inline",
117
- sourcefile: filePath,
118
- banner: `
119
- import { createRequire } from 'module';
120
- const require = createRequire(import.meta.url);`
281
+ return loadSync(urlStr, context, () => {
282
+ throw new Error("Chaining not supported");
121
283
  });
122
- return {
123
- format: "module",
124
- source: code,
125
- shortCircuit: true
126
- };
127
284
  }
128
285
  function loadSync(urlStr, context, nextLoadSync) {
129
- if (!urlStr.endsWith(".ts") && !urlStr.endsWith(".tsx")) {
130
- return nextLoadSync(urlStr, context);
131
- }
132
- const esbuildLoader = urlStr.endsWith(".tsx") ? "tsx" : "ts";
133
- const filePath = url.fileURLToPath(urlStr);
134
- const rawSource = fs.readFileSync(filePath, "utf8");
135
- const { code } = transformSync(rawSource, {
136
- loader: esbuildLoader,
137
- format: "esm",
138
- target: `node${process.versions.node}`,
139
- sourcemap: "inline",
140
- sourcefile: filePath,
141
- banner: `
286
+ if (urlStr.endsWith(".ts") || urlStr.endsWith(".tsx")) {
287
+ const esbuildLoader = urlStr.endsWith(".tsx") ? "tsx" : "ts";
288
+ const filePath = url.fileURLToPath(urlStr);
289
+ let rawSource = fs.readFileSync(filePath, "utf8");
290
+ if (config.emitDecoratorMetadata) {
291
+ rawSource = addMetadataDecorators(rawSource);
292
+ }
293
+ let banner = `
142
294
  import { createRequire } from 'module';
143
- const require = createRequire(import.meta.url);`
144
- });
145
- return {
146
- format: "module",
147
- source: code,
148
- shortCircuit: true
149
- };
295
+ const require = createRequire(import.meta.url);
296
+ `;
297
+ if (config.emitDecoratorMetadata) {
298
+ banner += `
299
+ var __metadata = (this && this.__metadata) || function (k, v) {
300
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
301
+ };
302
+ `;
303
+ }
304
+ const transformOptions = {
305
+ loader: esbuildLoader,
306
+ format: "esm",
307
+ target: `node${process.versions.node}`,
308
+ sourcemap: "inline",
309
+ sourcefile: filePath,
310
+ banner,
311
+ tsconfigRaw: {
312
+ compilerOptions: {
313
+ experimentalDecorators: config.experimentalDecorators
314
+ }
315
+ }
316
+ };
317
+ const { code } = transformSync(rawSource, transformOptions);
318
+ return {
319
+ format: "module",
320
+ source: code,
321
+ shortCircuit: true
322
+ };
323
+ } else {
324
+ const format = getFormatSync(urlStr);
325
+ let source;
326
+ if (format !== "builtin") {
327
+ const filePath = url.fileURLToPath(urlStr);
328
+ source = fs.readFileSync(filePath);
329
+ }
330
+ return { format, source, shortCircuit: true };
331
+ }
150
332
  }
151
333
  function resolveSync(specifier, context) {
152
334
  let parentPath = process.cwd();
@@ -202,10 +384,8 @@ function resolveSync(specifier, context) {
202
384
  }
203
385
  }
204
386
  }
205
- throw Object.assign(
206
- new Error(`Cannot find module '${specifier}'`),
207
- { code: "ERR_MODULE_NOT_FOUND" }
208
- );
387
+ const resolvedUrl = resolveBareSync(specifier, parentPath);
388
+ return { url: resolvedUrl, shortCircuit: true };
209
389
  }
210
390
  export {
211
391
  initialize,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-arc",
3
- "version": "1.1.22",
3
+ "version": "1.1.24",
4
4
  "type": "module",
5
5
  "description": "A simple typescript runtime.",
6
6
  "main": "dist/bin.js",
@@ -20,6 +20,7 @@
20
20
  "dist"
21
21
  ],
22
22
  "devDependencies": {
23
- "@types/node": "^24.9.1"
23
+ "@types/node": "^24.9.1",
24
+ "reflect-metadata": "^0.2.2"
24
25
  }
25
26
  }