@marko/language-tools 1.0.2 → 2.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.
@@ -14,6 +14,5 @@ export interface ExtractScriptOptions {
14
14
  lookup: TaglibLookup;
15
15
  scriptLang: ScriptLang;
16
16
  runtimeTypesCode?: string;
17
- componentFilename?: string | undefined;
18
17
  }
19
18
  export declare function extractScript(opts: ExtractScriptOptions): import("../../util/extractor").Extracted;
@@ -0,0 +1 @@
1
+ export declare function getComponentFilename(from: string): string | undefined;
@@ -1,4 +1,4 @@
1
- import type TS from "typescript";
1
+ import type TS from "typescript/lib/tsserverlibrary";
2
2
  import type { Repeatable } from "../../../parser";
3
3
  export default function getJSDocInputType(comment: string, ts: typeof TS): {
4
4
  typeParameters: Repeatable<{
package/dist/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  export * from "./parser";
2
2
  export * from "./extractors/style";
3
3
  export * from "./extractors/script";
4
+ export * as Project from "./util/project";
5
+ export * as Processors from "./processors";
6
+ export { getExt } from "./util/get-ext";
7
+ export { isDefinitionFile } from "./util/is-definition-file";
4
8
  export { type Extracted } from "./util/extractor";
package/dist/index.js CHANGED
@@ -31,13 +31,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  NodeType: () => NodeType,
34
+ Processors: () => processors_exports,
35
+ Project: () => project_exports,
34
36
  ScriptLang: () => ScriptLang,
35
37
  UNFINISHED: () => UNFINISHED,
36
38
  extractScript: () => extractScript,
37
39
  extractStyle: () => extractStyle,
40
+ getExt: () => getExt,
38
41
  getLines: () => import_htmljs_parser2.getLines,
39
42
  getLocation: () => import_htmljs_parser2.getLocation,
40
43
  getPosition: () => import_htmljs_parser2.getPosition,
44
+ isDefinitionFile: () => isDefinitionFile,
41
45
  parse: () => parse
42
46
  });
43
47
  module.exports = __toCommonJS(src_exports);
@@ -701,13 +705,8 @@ var Extractor = class {
701
705
  }
702
706
  };
703
707
  var Extracted = class {
704
- #parsed;
705
- #generated;
706
- #sourceToGenerated;
707
- #generatedToSource;
708
- #cachedGeneratedLines;
709
708
  constructor(parsed, generated, tokens) {
710
- this.#parsed = parsed;
709
+ this.parsed = parsed;
711
710
  this.#generated = generated;
712
711
  if (tokens.length === 0) {
713
712
  this.#generatedToSource = this.#sourceToGenerated = emptyView;
@@ -718,6 +717,10 @@ var Extracted = class {
718
717
  );
719
718
  }
720
719
  }
720
+ #generated;
721
+ #sourceToGenerated;
722
+ #generatedToSource;
723
+ #cachedGeneratedLines;
721
724
  get #generatedLines() {
722
725
  return this.#cachedGeneratedLines || (this.#cachedGeneratedLines = (0, import_htmljs_parser2.getLines)(this.#generated));
723
726
  }
@@ -727,7 +730,7 @@ var Extracted = class {
727
730
  sourcePositionAt(generatedOffset) {
728
731
  const sourceOffset = this.sourceOffsetAt(generatedOffset);
729
732
  if (sourceOffset !== void 0)
730
- return this.#parsed.positionAt(sourceOffset);
733
+ return this.parsed.positionAt(sourceOffset);
731
734
  }
732
735
  sourceLocationAt(generatedStart, generatedEnd) {
733
736
  const sourceRange = this.#generatedToSource.rangeAt(
@@ -735,7 +738,7 @@ var Extracted = class {
735
738
  generatedEnd
736
739
  );
737
740
  if (sourceRange) {
738
- return this.#parsed.locationAt(sourceRange);
741
+ return this.parsed.locationAt(sourceRange);
739
742
  }
740
743
  }
741
744
  generatedOffsetAt(sourceOffset) {
@@ -1525,6 +1528,31 @@ function traverse(node, enter) {
1525
1528
  }
1526
1529
  }
1527
1530
 
1531
+ // src/extractors/script/util/get-component-filename.ts
1532
+ var import_fs = __toESM(require("fs"));
1533
+ var import_path = __toESM(require("path"));
1534
+ function getComponentFilename(from) {
1535
+ const dir = import_path.default.dirname(from);
1536
+ const nameNoExt = import_path.default.basename(from, ".marko");
1537
+ const isEntry = nameNoExt === "index";
1538
+ const componentFull = `${nameNoExt}.component.`;
1539
+ const componentBrowserFull = `${nameNoExt}.component-browser.`;
1540
+ const componentPartial = isEntry ? "component." : void 0;
1541
+ const componentBrowserPartial = isEntry ? "component-browser." : void 0;
1542
+ for (const entry of tryReaddirSync(dir)) {
1543
+ if (entry !== from && (isEntry && entry.startsWith(componentBrowserPartial) || entry.startsWith(componentPartial)) || entry.startsWith(componentBrowserFull) || entry.startsWith(componentFull)) {
1544
+ return import_path.default.join(dir, entry);
1545
+ }
1546
+ }
1547
+ }
1548
+ function tryReaddirSync(dir) {
1549
+ try {
1550
+ return import_fs.default.readdirSync(dir);
1551
+ } catch {
1552
+ return [];
1553
+ }
1554
+ }
1555
+
1528
1556
  // src/extractors/script/util/runtime-overrides.ts
1529
1557
  var RuntimeOverloads = /* @__PURE__ */ new Map();
1530
1558
  var commentsReg = /\/\*(?:[^*]+|\*[^/])*\*\//gm;
@@ -1684,13 +1712,14 @@ var ScriptExtractor = class {
1684
1712
  this.#scriptParser = new ScriptParser(parsed.filename, parsed.code);
1685
1713
  this.#read = parsed.read.bind(parsed);
1686
1714
  this.#mutationOffsets = crawlProgramScope(this.#parsed, this.#scriptParser);
1687
- this.#writeProgram(parsed.program, opts.componentFilename);
1715
+ this.#writeProgram(parsed.program);
1688
1716
  }
1689
1717
  end() {
1690
1718
  return this.#extractor.end();
1691
1719
  }
1692
- #writeProgram(program, componentFileName) {
1720
+ #writeProgram(program) {
1693
1721
  this.#writeCommentPragmas(program);
1722
+ const componentFileName = getComponentFilename(this.#filename);
1694
1723
  const inputType = this.#getInputType(program);
1695
1724
  let componentClassBody;
1696
1725
  for (const node of program.static) {
@@ -1748,7 +1777,7 @@ var ScriptExtractor = class {
1748
1777
  let typeParamsStr = "";
1749
1778
  let typeArgsStr = "";
1750
1779
  let jsDocTemplateTagsStr = "";
1751
- const hasComponent = componentClassBody || componentFileName;
1780
+ const isExternalComponentFile = !componentClassBody && componentFileName !== void 0;
1752
1781
  if (inputType) {
1753
1782
  if (inputType.typeParameters) {
1754
1783
  let sep = SEP_EMPTY;
@@ -1770,17 +1799,17 @@ var ScriptExtractor = class {
1770
1799
  } else {
1771
1800
  if (this.#scriptLang === "ts" /* ts */) {
1772
1801
  this.#extractor.write(
1773
- hasComponent ? "export type Input = Component['input'];\n" : `export interface Input {}
1802
+ isExternalComponentFile ? "export type Input = Component['input'];\n" : `export interface Input {}
1774
1803
  `
1775
1804
  );
1776
1805
  } else {
1777
1806
  this.#extractor.write(
1778
- `/** @typedef {${hasComponent ? "Component['input']" : "Record<string, unknown>"}} Input */
1807
+ `/** @typedef {${isExternalComponentFile ? "Component['input']" : "Record<string, unknown>"}} Input */
1779
1808
  `
1780
1809
  );
1781
1810
  }
1782
1811
  }
1783
- if (!componentClassBody && componentFileName) {
1812
+ if (isExternalComponentFile) {
1784
1813
  if (this.#scriptLang === "ts" /* ts */) {
1785
1814
  this.#extractor.write(
1786
1815
  `import type Component from "${stripExt(
@@ -1800,11 +1829,11 @@ var ScriptExtractor = class {
1800
1829
  const body2 = componentClassBody || " {}";
1801
1830
  if (this.#scriptLang === "ts" /* ts */) {
1802
1831
  this.#extractor.write(
1803
- `abstract class Component${typeParamsStr} extends Marko.Component<${hasComponent && !inputType ? "{}" : `Input${typeArgsStr}`}>`
1832
+ `abstract class Component${typeParamsStr} extends Marko.Component<Input${typeArgsStr}>`
1804
1833
  ).copy(body2).write("\nexport { type Component }\n");
1805
1834
  } else {
1806
1835
  this.#extractor.write(`/**${jsDocTemplateTagsStr}
1807
- * @extends {Marko.Component${hasComponent && !inputType ? "" : `<Input${typeArgsStr}>`}}
1836
+ * @extends {Marko.Component<Input${typeArgsStr}>}
1808
1837
  * @abstract
1809
1838
  */
1810
1839
  `);
@@ -2848,15 +2877,413 @@ function removeNewLines(str) {
2848
2877
  function isEmptyRange(range) {
2849
2878
  return range.start === range.end;
2850
2879
  }
2880
+
2881
+ // src/util/project.ts
2882
+ var project_exports = {};
2883
+ __export(project_exports, {
2884
+ clearCaches: () => clearCaches,
2885
+ getCache: () => getCache,
2886
+ getCompiler: () => getCompiler,
2887
+ getConfig: () => getConfig,
2888
+ getScriptLang: () => getScriptLang,
2889
+ getTagLookup: () => getTagLookup,
2890
+ getTypeLibs: () => getTypeLibs
2891
+ });
2892
+ var import_path2 = __toESM(require("path"));
2893
+ var import_module = require("module");
2894
+ var defaultCompiler = __toESM(require("@marko/compiler"));
2895
+ var defaultConfig = __toESM(require("@marko/compiler/config"));
2896
+ var defaultTranslator = __toESM(require("@marko/translator-default"));
2897
+ var import_strip_json_comments = __toESM(require("strip-json-comments"));
2898
+ var ignoreErrors = (_err) => {
2899
+ };
2900
+ var metaByDir = /* @__PURE__ */ new Map();
2901
+ var metaByCompiler = /* @__PURE__ */ new Map();
2902
+ var defaultMeta = {
2903
+ compiler: defaultCompiler,
2904
+ config: {
2905
+ ...defaultConfig,
2906
+ cache: /* @__PURE__ */ new Map(),
2907
+ translator: defaultTranslator
2908
+ }
2909
+ };
2910
+ defaultCompiler.configure(defaultMeta.config);
2911
+ function getCompiler(dir) {
2912
+ return getMeta(dir).compiler;
2913
+ }
2914
+ function getCache(dir) {
2915
+ return getMeta(dir).config.cache;
2916
+ }
2917
+ function getConfig(dir) {
2918
+ return getMeta(dir).config;
2919
+ }
2920
+ function getTagLookup(dir) {
2921
+ return getTagLookupForProject(getMeta(dir), dir);
2922
+ }
2923
+ function getTypeLibs(rootDir, ts, host) {
2924
+ const config = getConfig(rootDir);
2925
+ let typeLibs = config.cache.get(getTypeLibs);
2926
+ if (typeLibs)
2927
+ return typeLibs;
2928
+ const resolveTypeCompilerOptions = {
2929
+ moduleResolution: ts.ModuleResolutionKind.Bundler
2930
+ };
2931
+ const markoRunGeneratedTypesFile = import_path2.default.join(
2932
+ rootDir,
2933
+ ".marko-run/routes.d.ts"
2934
+ );
2935
+ const resolveFromFile = import_path2.default.join(rootDir, "_.d.ts");
2936
+ const { resolvedTypeReferenceDirective: resolvedInternalTypes } = ts.resolveTypeReferenceDirective(
2937
+ "@marko/language-tools/marko.internal.d.ts",
2938
+ resolveFromFile,
2939
+ resolveTypeCompilerOptions,
2940
+ host
2941
+ );
2942
+ const { resolvedTypeReferenceDirective: resolvedMarkoTypes } = ts.resolveTypeReferenceDirective(
2943
+ config.translator.runtimeTypes || "marko",
2944
+ resolveFromFile,
2945
+ resolveTypeCompilerOptions,
2946
+ host
2947
+ );
2948
+ const { resolvedTypeReferenceDirective: resolvedMarkoRunTypes } = ts.resolveTypeReferenceDirective(
2949
+ "@marko/run",
2950
+ resolveFromFile,
2951
+ resolveTypeCompilerOptions,
2952
+ host
2953
+ );
2954
+ const internalTypesFile = resolvedInternalTypes == null ? void 0 : resolvedInternalTypes.resolvedFileName;
2955
+ const markoTypesFile = resolvedMarkoTypes == null ? void 0 : resolvedMarkoTypes.resolvedFileName;
2956
+ const markoRunTypesFile = resolvedMarkoRunTypes == null ? void 0 : resolvedMarkoRunTypes.resolvedFileName;
2957
+ if (!internalTypesFile || !markoTypesFile) {
2958
+ throw new Error("Could not resolve marko type files.");
2959
+ }
2960
+ config.cache.set(
2961
+ getTypeLibs,
2962
+ typeLibs = {
2963
+ internalTypesFile,
2964
+ markoTypesFile,
2965
+ markoTypesCode: host.readFile(markoTypesFile) || "",
2966
+ markoRunTypesFile,
2967
+ markoRunGeneratedTypesFile: host.fileExists(markoRunGeneratedTypesFile) ? markoRunGeneratedTypesFile : void 0
2968
+ }
2969
+ );
2970
+ return typeLibs;
2971
+ }
2972
+ function getScriptLang(fileName, defaultScriptLang, ts, host) {
2973
+ if (fileName.endsWith(".d.marko"))
2974
+ return "ts" /* ts */;
2975
+ const dir = import_path2.default.dirname(fileName);
2976
+ const config = getConfig(dir);
2977
+ const cache = config.cache.get(getScriptLang);
2978
+ let scriptLang = cache == null ? void 0 : cache.get(dir);
2979
+ if (!scriptLang) {
2980
+ const configPath = ts.findConfigFile(dir, host.fileExists, "marko.json");
2981
+ if (configPath) {
2982
+ try {
2983
+ const configSource = host.readFile(configPath);
2984
+ if (configSource) {
2985
+ const config2 = tryParseJSONWithComments(configSource);
2986
+ if (config2) {
2987
+ const definedScriptLang = config2["script-lang"] || config2.scriptLang;
2988
+ if (definedScriptLang !== void 0) {
2989
+ scriptLang = definedScriptLang === "ts" /* ts */ ? "ts" /* ts */ : "js" /* js */;
2990
+ }
2991
+ }
2992
+ }
2993
+ } catch {
2994
+ }
2995
+ }
2996
+ if (scriptLang === void 0) {
2997
+ scriptLang = /[/\\]node_modules[/\\]/.test(dir) ? "js" /* js */ : defaultScriptLang;
2998
+ }
2999
+ if (cache) {
3000
+ cache.set(dir, scriptLang);
3001
+ } else {
3002
+ config.cache.set(getScriptLang, /* @__PURE__ */ new Map([[dir, scriptLang]]));
3003
+ }
3004
+ }
3005
+ return scriptLang;
3006
+ }
3007
+ function clearCaches() {
3008
+ clearCacheForMeta(defaultMeta);
3009
+ for (const project of metaByCompiler.values()) {
3010
+ clearCacheForMeta(project);
3011
+ }
3012
+ }
3013
+ function getMeta(dir) {
3014
+ if (!dir)
3015
+ return defaultMeta;
3016
+ let cached = metaByDir.get(dir);
3017
+ if (!cached) {
3018
+ try {
3019
+ const require2 = (0, import_module.createRequire)(dir);
3020
+ const compilerConfigPath = require2.resolve("@marko/compiler/config");
3021
+ cached = metaByCompiler.get(compilerConfigPath);
3022
+ if (!cached) {
3023
+ const compiler = require2(import_path2.default.join(
3024
+ compilerConfigPath,
3025
+ ".."
3026
+ ));
3027
+ const config = interopDefault(
3028
+ require2(compilerConfigPath)
3029
+ );
3030
+ cached = {
3031
+ compiler,
3032
+ config: {
3033
+ ...config,
3034
+ cache: /* @__PURE__ */ new Map(),
3035
+ translator: require2(config.translator)
3036
+ }
3037
+ };
3038
+ compiler.configure(cached.config);
3039
+ metaByCompiler.set(compilerConfigPath, cached);
3040
+ }
3041
+ } catch {
3042
+ cached = defaultMeta;
3043
+ }
3044
+ metaByDir.set(dir, cached);
3045
+ }
3046
+ return cached;
3047
+ }
3048
+ function getTagLookupForProject(meta, dir) {
3049
+ const cache = meta.config.cache.get(getTagLookupForProject);
3050
+ let lookup = cache == null ? void 0 : cache.get(dir);
3051
+ if (lookup === void 0) {
3052
+ try {
3053
+ lookup = meta.compiler.taglib.buildLookup(
3054
+ dir,
3055
+ meta.config.translator,
3056
+ ignoreErrors
3057
+ );
3058
+ } catch {
3059
+ if (meta !== defaultMeta) {
3060
+ lookup = getTagLookupForProject(defaultMeta, dir);
3061
+ }
3062
+ }
3063
+ if (cache) {
3064
+ cache.set(dir, lookup);
3065
+ } else {
3066
+ meta.config.cache.set(getTagLookupForProject, /* @__PURE__ */ new Map([[dir, lookup]]));
3067
+ }
3068
+ }
3069
+ return lookup;
3070
+ }
3071
+ function clearCacheForMeta(meta) {
3072
+ meta.config.cache.clear();
3073
+ meta.compiler.taglib.clearCaches();
3074
+ }
3075
+ function tryParseJSONWithComments(content) {
3076
+ try {
3077
+ return JSON.parse((0, import_strip_json_comments.default)(content));
3078
+ } catch {
3079
+ return void 0;
3080
+ }
3081
+ }
3082
+ function interopDefault(mod) {
3083
+ return mod.default || mod;
3084
+ }
3085
+
3086
+ // src/processors/index.ts
3087
+ var processors_exports = {};
3088
+ __export(processors_exports, {
3089
+ create: () => create,
3090
+ extensions: () => extensions,
3091
+ has: () => has
3092
+ });
3093
+
3094
+ // src/util/get-ext.ts
3095
+ function getExt(fileName) {
3096
+ const extIndex = fileName.lastIndexOf(".");
3097
+ if (extIndex !== -1)
3098
+ return fileName.slice(extIndex);
3099
+ }
3100
+
3101
+ // src/processors/marko.ts
3102
+ var import_path3 = __toESM(require("path"));
3103
+ var marko_default = {
3104
+ extension: ".marko",
3105
+ create({ ts, host, configFile }) {
3106
+ const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ts.sys.getCurrentDirectory();
3107
+ const defaultScriptLang = configFile && /tsconfig.json$/.test(configFile) ? "ts" /* ts */ : "js" /* js */;
3108
+ const runtimeTypes = getTypeLibs(currentDirectory, ts, host);
3109
+ const rootNames = [
3110
+ runtimeTypes.internalTypesFile,
3111
+ runtimeTypes.markoTypesFile
3112
+ ];
3113
+ if (runtimeTypes.markoRunTypesFile) {
3114
+ rootNames.push(runtimeTypes.markoRunTypesFile);
3115
+ }
3116
+ if (runtimeTypes.markoRunGeneratedTypesFile) {
3117
+ rootNames.push(runtimeTypes.markoRunGeneratedTypesFile);
3118
+ }
3119
+ return {
3120
+ getRootNames() {
3121
+ return rootNames;
3122
+ },
3123
+ getScriptExtension(fileName) {
3124
+ return getScriptLang(fileName, defaultScriptLang, ts, host) === "ts" /* ts */ ? ts.Extension.Ts : ts.Extension.Js;
3125
+ },
3126
+ getScriptKind(fileName) {
3127
+ return getScriptLang(fileName, defaultScriptLang, ts, host) === "ts" /* ts */ ? ts.ScriptKind.TS : ts.ScriptKind.JS;
3128
+ },
3129
+ extract(fileName, code) {
3130
+ const dir = import_path3.default.dirname(fileName);
3131
+ const parsed = parse(code, fileName);
3132
+ return extractScript({
3133
+ ts,
3134
+ parsed,
3135
+ lookup: getTagLookup(dir),
3136
+ scriptLang: getScriptLang(
3137
+ fileName,
3138
+ defaultScriptLang,
3139
+ ts,
3140
+ host
3141
+ ),
3142
+ runtimeTypesCode: runtimeTypes.markoTypesCode
3143
+ });
3144
+ },
3145
+ print({ extracted: { parsed } }) {
3146
+ const { code, map } = getCompiler(
3147
+ import_path3.default.dirname(parsed.filename)
3148
+ ).compileSync(parsed.code, parsed.filename, {
3149
+ output: "source",
3150
+ stripTypes: true,
3151
+ sourceMaps: true
3152
+ });
3153
+ return { code, map };
3154
+ },
3155
+ printTypes({ printer, typeChecker, sourceFile, formatSettings }) {
3156
+ var _a, _b, _c;
3157
+ let code = "";
3158
+ const nlChar = formatSettings.newLineCharacter;
3159
+ const tabChar = formatSettings.convertTabsToSpaces ? " ".repeat(formatSettings.indentSize) : " ";
3160
+ let defaultExport;
3161
+ let defaultExportId;
3162
+ let componentImpl;
3163
+ let internalRenderImpl;
3164
+ for (const statement of sourceFile.statements) {
3165
+ if (ts.isExportAssignment(statement)) {
3166
+ defaultExport = statement;
3167
+ defaultExportId = ts.isIdentifier(statement.expression) ? statement.expression.escapedText : void 0;
3168
+ } else if (ts.isClassDeclaration(statement) && ((_a = statement.name) == null ? void 0 : _a.escapedText) === "Component") {
3169
+ componentImpl = statement;
3170
+ } else if (ts.isFunctionDeclaration(statement) && ((_b = statement.name) == null ? void 0 : _b.escapedText) === "___marko_internal_template") {
3171
+ internalRenderImpl = statement;
3172
+ }
3173
+ }
3174
+ for (const statement of sourceFile.statements) {
3175
+ if (statement === defaultExport || // skips the generated `export default ...`.
3176
+ statement === componentImpl || // skips the generated `class {}` since it needs special processing.
3177
+ statement === internalRenderImpl || // skips the internal template render code.
3178
+ isExportComponentType(statement) || // skips the generated `export { type Component }`.
3179
+ isImportComponentType(statement) || // skips the generated `import type Component from "..."`.
3180
+ isExportEmptyInputType(statement) || // skips empty exported Input, eg `export type Input = {}` or `export interface Input {}`.
3181
+ isExportInputTypeAsComponentInput(statement) || // skips outputing `export type Input = Component["input"]` since it's inferred.
3182
+ defaultExportId && // If the `export default` was an identifier, we also remove the variable that declared the identifier.
3183
+ isVariableStatementForName(statement, defaultExportId)) {
3184
+ continue;
3185
+ }
3186
+ const printed = printer.printNode(
3187
+ ts.EmitHint.Unspecified,
3188
+ statement,
3189
+ sourceFile
3190
+ );
3191
+ if (!/^(?:import|export) /.test(printed))
3192
+ code += "static ";
3193
+ code += printed + nlChar;
3194
+ }
3195
+ if (componentImpl == null ? void 0 : componentImpl.members.length) {
3196
+ code += `class {${nlChar}`;
3197
+ for (const member of componentImpl.members) {
3198
+ if (ts.isPropertyDeclaration(member)) {
3199
+ code += `${tabChar}declare ${printer.printNode(ts.EmitHint.Unspecified, member, sourceFile) + nlChar}`;
3200
+ } else if (ts.isMethodDeclaration(member) || ts.isGetAccessorDeclaration(member) || ts.isSetAccessorDeclaration(member)) {
3201
+ code += `${tabChar + printer.printNode(ts.EmitHint.Unspecified, member, sourceFile).replace(/;\s*$/, "")} { return ${castType("any")}; }${nlChar}`;
3202
+ } else if (ts.isIndexSignatureDeclaration(member)) {
3203
+ code += tabChar + printer.printNode(ts.EmitHint.Unspecified, member, sourceFile) + nlChar;
3204
+ }
3205
+ }
3206
+ code += `}${nlChar}`;
3207
+ }
3208
+ if (internalRenderImpl) {
3209
+ const returnType = (_c = typeChecker.getSignatureFromDeclaration(internalRenderImpl)) == null ? void 0 : _c.getReturnType();
3210
+ if (returnType) {
3211
+ const props = returnType.getProperties();
3212
+ const valueType = props.length === 1 && props[0].name === "value" && typeChecker.getPropertyOfType(returnType, "value") || void 0;
3213
+ code += "<return ";
3214
+ if (valueType) {
3215
+ code += `= ${castType(
3216
+ typeChecker.typeToString(typeChecker.getTypeOfSymbol(valueType))
3217
+ )}`;
3218
+ } else {
3219
+ code += `...${castType(typeChecker.typeToString(returnType))}`;
3220
+ }
3221
+ code += `/>${nlChar}`;
3222
+ }
3223
+ }
3224
+ return { code };
3225
+ }
3226
+ };
3227
+ function isImportComponentType(statement) {
3228
+ var _a, _b;
3229
+ return ts.isImportDeclaration(statement) && ((_b = (_a = statement.importClause) == null ? void 0 : _a.name) == null ? void 0 : _b.escapedText) === "Component";
3230
+ }
3231
+ function isExportInputTypeAsComponentInput(statement) {
3232
+ return ts.isTypeAliasDeclaration(statement) && statement.name.escapedText === "Input" && ts.isIndexedAccessTypeNode(statement.type) && ts.isTypeReferenceNode(statement.type.objectType) && ts.isIdentifier(statement.type.objectType.typeName) && statement.type.objectType.typeName.escapedText === "Component" && ts.isLiteralTypeNode(statement.type.indexType) && ts.isStringLiteral(statement.type.indexType.literal) && statement.type.indexType.literal.text === "input";
3233
+ }
3234
+ function isExportEmptyInputType(statement) {
3235
+ return ts.isTypeAliasDeclaration(statement) && statement.name.escapedText === "Input" && ts.isTypeLiteralNode(statement.type) && !statement.typeParameters && statement.type.members.length === 0 || ts.isInterfaceDeclaration(statement) && statement.name.escapedText === "Input" && !statement.typeParameters && statement.members.length === 0;
3236
+ }
3237
+ function isExportComponentType(statement) {
3238
+ return ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.length === 1 && statement.exportClause.elements[0].name.escapedText === "Component";
3239
+ }
3240
+ function isVariableStatementForName(statement, name) {
3241
+ if (ts.isVariableStatement(statement)) {
3242
+ for (const decl of statement.declarationList.declarations) {
3243
+ if (ts.isIdentifier(decl.name) && decl.name.escapedText === name) {
3244
+ return true;
3245
+ }
3246
+ }
3247
+ }
3248
+ }
3249
+ }
3250
+ };
3251
+ function castType(type) {
3252
+ if (type === "any") {
3253
+ return "1 as any";
3254
+ }
3255
+ return `(1 as any as ${type})`;
3256
+ }
3257
+
3258
+ // src/processors/index.ts
3259
+ var extensions = [marko_default.extension];
3260
+ function create(options) {
3261
+ return {
3262
+ [marko_default.extension]: marko_default.create(options)
3263
+ };
3264
+ }
3265
+ function has(fileName) {
3266
+ const ext = getExt(fileName);
3267
+ return !!(ext && extensions.includes(ext));
3268
+ }
3269
+
3270
+ // src/util/is-definition-file.ts
3271
+ function isDefinitionFile(fileName) {
3272
+ return /\.d\.[^.]+$/.test(fileName);
3273
+ }
2851
3274
  // Annotate the CommonJS export names for ESM import in node:
2852
3275
  0 && (module.exports = {
2853
3276
  NodeType,
3277
+ Processors,
3278
+ Project,
2854
3279
  ScriptLang,
2855
3280
  UNFINISHED,
2856
3281
  extractScript,
2857
3282
  extractStyle,
3283
+ getExt,
2858
3284
  getLines,
2859
3285
  getLocation,
2860
3286
  getPosition,
3287
+ isDefinitionFile,
2861
3288
  parse
2862
3289
  });
package/dist/index.mjs CHANGED
@@ -1,3 +1,9 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
1
7
  // src/parser.ts
2
8
  import { TagType, createParser } from "htmljs-parser";
3
9
 
@@ -661,13 +667,8 @@ var Extractor = class {
661
667
  }
662
668
  };
663
669
  var Extracted = class {
664
- #parsed;
665
- #generated;
666
- #sourceToGenerated;
667
- #generatedToSource;
668
- #cachedGeneratedLines;
669
670
  constructor(parsed, generated, tokens) {
670
- this.#parsed = parsed;
671
+ this.parsed = parsed;
671
672
  this.#generated = generated;
672
673
  if (tokens.length === 0) {
673
674
  this.#generatedToSource = this.#sourceToGenerated = emptyView;
@@ -678,6 +679,10 @@ var Extracted = class {
678
679
  );
679
680
  }
680
681
  }
682
+ #generated;
683
+ #sourceToGenerated;
684
+ #generatedToSource;
685
+ #cachedGeneratedLines;
681
686
  get #generatedLines() {
682
687
  return this.#cachedGeneratedLines || (this.#cachedGeneratedLines = getLines(this.#generated));
683
688
  }
@@ -687,7 +692,7 @@ var Extracted = class {
687
692
  sourcePositionAt(generatedOffset) {
688
693
  const sourceOffset = this.sourceOffsetAt(generatedOffset);
689
694
  if (sourceOffset !== void 0)
690
- return this.#parsed.positionAt(sourceOffset);
695
+ return this.parsed.positionAt(sourceOffset);
691
696
  }
692
697
  sourceLocationAt(generatedStart, generatedEnd) {
693
698
  const sourceRange = this.#generatedToSource.rangeAt(
@@ -695,7 +700,7 @@ var Extracted = class {
695
700
  generatedEnd
696
701
  );
697
702
  if (sourceRange) {
698
- return this.#parsed.locationAt(sourceRange);
703
+ return this.parsed.locationAt(sourceRange);
699
704
  }
700
705
  }
701
706
  generatedOffsetAt(sourceOffset) {
@@ -1492,6 +1497,31 @@ function traverse(node, enter) {
1492
1497
  }
1493
1498
  }
1494
1499
 
1500
+ // src/extractors/script/util/get-component-filename.ts
1501
+ import fs from "fs";
1502
+ import path from "path";
1503
+ function getComponentFilename(from) {
1504
+ const dir = path.dirname(from);
1505
+ const nameNoExt = path.basename(from, ".marko");
1506
+ const isEntry = nameNoExt === "index";
1507
+ const componentFull = `${nameNoExt}.component.`;
1508
+ const componentBrowserFull = `${nameNoExt}.component-browser.`;
1509
+ const componentPartial = isEntry ? "component." : void 0;
1510
+ const componentBrowserPartial = isEntry ? "component-browser." : void 0;
1511
+ for (const entry of tryReaddirSync(dir)) {
1512
+ if (entry !== from && (isEntry && entry.startsWith(componentBrowserPartial) || entry.startsWith(componentPartial)) || entry.startsWith(componentBrowserFull) || entry.startsWith(componentFull)) {
1513
+ return path.join(dir, entry);
1514
+ }
1515
+ }
1516
+ }
1517
+ function tryReaddirSync(dir) {
1518
+ try {
1519
+ return fs.readdirSync(dir);
1520
+ } catch {
1521
+ return [];
1522
+ }
1523
+ }
1524
+
1495
1525
  // src/extractors/script/util/runtime-overrides.ts
1496
1526
  var RuntimeOverloads = /* @__PURE__ */ new Map();
1497
1527
  var commentsReg = /\/\*(?:[^*]+|\*[^/])*\*\//gm;
@@ -1651,13 +1681,14 @@ var ScriptExtractor = class {
1651
1681
  this.#scriptParser = new ScriptParser(parsed.filename, parsed.code);
1652
1682
  this.#read = parsed.read.bind(parsed);
1653
1683
  this.#mutationOffsets = crawlProgramScope(this.#parsed, this.#scriptParser);
1654
- this.#writeProgram(parsed.program, opts.componentFilename);
1684
+ this.#writeProgram(parsed.program);
1655
1685
  }
1656
1686
  end() {
1657
1687
  return this.#extractor.end();
1658
1688
  }
1659
- #writeProgram(program, componentFileName) {
1689
+ #writeProgram(program) {
1660
1690
  this.#writeCommentPragmas(program);
1691
+ const componentFileName = getComponentFilename(this.#filename);
1661
1692
  const inputType = this.#getInputType(program);
1662
1693
  let componentClassBody;
1663
1694
  for (const node of program.static) {
@@ -1715,7 +1746,7 @@ var ScriptExtractor = class {
1715
1746
  let typeParamsStr = "";
1716
1747
  let typeArgsStr = "";
1717
1748
  let jsDocTemplateTagsStr = "";
1718
- const hasComponent = componentClassBody || componentFileName;
1749
+ const isExternalComponentFile = !componentClassBody && componentFileName !== void 0;
1719
1750
  if (inputType) {
1720
1751
  if (inputType.typeParameters) {
1721
1752
  let sep = SEP_EMPTY;
@@ -1737,17 +1768,17 @@ var ScriptExtractor = class {
1737
1768
  } else {
1738
1769
  if (this.#scriptLang === "ts" /* ts */) {
1739
1770
  this.#extractor.write(
1740
- hasComponent ? "export type Input = Component['input'];\n" : `export interface Input {}
1771
+ isExternalComponentFile ? "export type Input = Component['input'];\n" : `export interface Input {}
1741
1772
  `
1742
1773
  );
1743
1774
  } else {
1744
1775
  this.#extractor.write(
1745
- `/** @typedef {${hasComponent ? "Component['input']" : "Record<string, unknown>"}} Input */
1776
+ `/** @typedef {${isExternalComponentFile ? "Component['input']" : "Record<string, unknown>"}} Input */
1746
1777
  `
1747
1778
  );
1748
1779
  }
1749
1780
  }
1750
- if (!componentClassBody && componentFileName) {
1781
+ if (isExternalComponentFile) {
1751
1782
  if (this.#scriptLang === "ts" /* ts */) {
1752
1783
  this.#extractor.write(
1753
1784
  `import type Component from "${stripExt(
@@ -1767,11 +1798,11 @@ var ScriptExtractor = class {
1767
1798
  const body2 = componentClassBody || " {}";
1768
1799
  if (this.#scriptLang === "ts" /* ts */) {
1769
1800
  this.#extractor.write(
1770
- `abstract class Component${typeParamsStr} extends Marko.Component<${hasComponent && !inputType ? "{}" : `Input${typeArgsStr}`}>`
1801
+ `abstract class Component${typeParamsStr} extends Marko.Component<Input${typeArgsStr}>`
1771
1802
  ).copy(body2).write("\nexport { type Component }\n");
1772
1803
  } else {
1773
1804
  this.#extractor.write(`/**${jsDocTemplateTagsStr}
1774
- * @extends {Marko.Component${hasComponent && !inputType ? "" : `<Input${typeArgsStr}>`}}
1805
+ * @extends {Marko.Component<Input${typeArgsStr}>}
1775
1806
  * @abstract
1776
1807
  */
1777
1808
  `);
@@ -2815,14 +2846,412 @@ function removeNewLines(str) {
2815
2846
  function isEmptyRange(range) {
2816
2847
  return range.start === range.end;
2817
2848
  }
2849
+
2850
+ // src/util/project.ts
2851
+ var project_exports = {};
2852
+ __export(project_exports, {
2853
+ clearCaches: () => clearCaches,
2854
+ getCache: () => getCache,
2855
+ getCompiler: () => getCompiler,
2856
+ getConfig: () => getConfig,
2857
+ getScriptLang: () => getScriptLang,
2858
+ getTagLookup: () => getTagLookup,
2859
+ getTypeLibs: () => getTypeLibs
2860
+ });
2861
+ import path2 from "path";
2862
+ import { createRequire } from "module";
2863
+ import * as defaultCompiler from "@marko/compiler";
2864
+ import * as defaultConfig from "@marko/compiler/config";
2865
+ import * as defaultTranslator from "@marko/translator-default";
2866
+ import stripJSONComments from "strip-json-comments";
2867
+ var ignoreErrors = (_err) => {
2868
+ };
2869
+ var metaByDir = /* @__PURE__ */ new Map();
2870
+ var metaByCompiler = /* @__PURE__ */ new Map();
2871
+ var defaultMeta = {
2872
+ compiler: defaultCompiler,
2873
+ config: {
2874
+ ...defaultConfig,
2875
+ cache: /* @__PURE__ */ new Map(),
2876
+ translator: defaultTranslator
2877
+ }
2878
+ };
2879
+ defaultCompiler.configure(defaultMeta.config);
2880
+ function getCompiler(dir) {
2881
+ return getMeta(dir).compiler;
2882
+ }
2883
+ function getCache(dir) {
2884
+ return getMeta(dir).config.cache;
2885
+ }
2886
+ function getConfig(dir) {
2887
+ return getMeta(dir).config;
2888
+ }
2889
+ function getTagLookup(dir) {
2890
+ return getTagLookupForProject(getMeta(dir), dir);
2891
+ }
2892
+ function getTypeLibs(rootDir, ts, host) {
2893
+ const config = getConfig(rootDir);
2894
+ let typeLibs = config.cache.get(getTypeLibs);
2895
+ if (typeLibs)
2896
+ return typeLibs;
2897
+ const resolveTypeCompilerOptions = {
2898
+ moduleResolution: ts.ModuleResolutionKind.Bundler
2899
+ };
2900
+ const markoRunGeneratedTypesFile = path2.join(
2901
+ rootDir,
2902
+ ".marko-run/routes.d.ts"
2903
+ );
2904
+ const resolveFromFile = path2.join(rootDir, "_.d.ts");
2905
+ const { resolvedTypeReferenceDirective: resolvedInternalTypes } = ts.resolveTypeReferenceDirective(
2906
+ "@marko/language-tools/marko.internal.d.ts",
2907
+ resolveFromFile,
2908
+ resolveTypeCompilerOptions,
2909
+ host
2910
+ );
2911
+ const { resolvedTypeReferenceDirective: resolvedMarkoTypes } = ts.resolveTypeReferenceDirective(
2912
+ config.translator.runtimeTypes || "marko",
2913
+ resolveFromFile,
2914
+ resolveTypeCompilerOptions,
2915
+ host
2916
+ );
2917
+ const { resolvedTypeReferenceDirective: resolvedMarkoRunTypes } = ts.resolveTypeReferenceDirective(
2918
+ "@marko/run",
2919
+ resolveFromFile,
2920
+ resolveTypeCompilerOptions,
2921
+ host
2922
+ );
2923
+ const internalTypesFile = resolvedInternalTypes == null ? void 0 : resolvedInternalTypes.resolvedFileName;
2924
+ const markoTypesFile = resolvedMarkoTypes == null ? void 0 : resolvedMarkoTypes.resolvedFileName;
2925
+ const markoRunTypesFile = resolvedMarkoRunTypes == null ? void 0 : resolvedMarkoRunTypes.resolvedFileName;
2926
+ if (!internalTypesFile || !markoTypesFile) {
2927
+ throw new Error("Could not resolve marko type files.");
2928
+ }
2929
+ config.cache.set(
2930
+ getTypeLibs,
2931
+ typeLibs = {
2932
+ internalTypesFile,
2933
+ markoTypesFile,
2934
+ markoTypesCode: host.readFile(markoTypesFile) || "",
2935
+ markoRunTypesFile,
2936
+ markoRunGeneratedTypesFile: host.fileExists(markoRunGeneratedTypesFile) ? markoRunGeneratedTypesFile : void 0
2937
+ }
2938
+ );
2939
+ return typeLibs;
2940
+ }
2941
+ function getScriptLang(fileName, defaultScriptLang, ts, host) {
2942
+ if (fileName.endsWith(".d.marko"))
2943
+ return "ts" /* ts */;
2944
+ const dir = path2.dirname(fileName);
2945
+ const config = getConfig(dir);
2946
+ const cache = config.cache.get(getScriptLang);
2947
+ let scriptLang = cache == null ? void 0 : cache.get(dir);
2948
+ if (!scriptLang) {
2949
+ const configPath = ts.findConfigFile(dir, host.fileExists, "marko.json");
2950
+ if (configPath) {
2951
+ try {
2952
+ const configSource = host.readFile(configPath);
2953
+ if (configSource) {
2954
+ const config2 = tryParseJSONWithComments(configSource);
2955
+ if (config2) {
2956
+ const definedScriptLang = config2["script-lang"] || config2.scriptLang;
2957
+ if (definedScriptLang !== void 0) {
2958
+ scriptLang = definedScriptLang === "ts" /* ts */ ? "ts" /* ts */ : "js" /* js */;
2959
+ }
2960
+ }
2961
+ }
2962
+ } catch {
2963
+ }
2964
+ }
2965
+ if (scriptLang === void 0) {
2966
+ scriptLang = /[/\\]node_modules[/\\]/.test(dir) ? "js" /* js */ : defaultScriptLang;
2967
+ }
2968
+ if (cache) {
2969
+ cache.set(dir, scriptLang);
2970
+ } else {
2971
+ config.cache.set(getScriptLang, /* @__PURE__ */ new Map([[dir, scriptLang]]));
2972
+ }
2973
+ }
2974
+ return scriptLang;
2975
+ }
2976
+ function clearCaches() {
2977
+ clearCacheForMeta(defaultMeta);
2978
+ for (const project of metaByCompiler.values()) {
2979
+ clearCacheForMeta(project);
2980
+ }
2981
+ }
2982
+ function getMeta(dir) {
2983
+ if (!dir)
2984
+ return defaultMeta;
2985
+ let cached = metaByDir.get(dir);
2986
+ if (!cached) {
2987
+ try {
2988
+ const require2 = createRequire(dir);
2989
+ const compilerConfigPath = require2.resolve("@marko/compiler/config");
2990
+ cached = metaByCompiler.get(compilerConfigPath);
2991
+ if (!cached) {
2992
+ const compiler = require2(path2.join(
2993
+ compilerConfigPath,
2994
+ ".."
2995
+ ));
2996
+ const config = interopDefault(
2997
+ require2(compilerConfigPath)
2998
+ );
2999
+ cached = {
3000
+ compiler,
3001
+ config: {
3002
+ ...config,
3003
+ cache: /* @__PURE__ */ new Map(),
3004
+ translator: require2(config.translator)
3005
+ }
3006
+ };
3007
+ compiler.configure(cached.config);
3008
+ metaByCompiler.set(compilerConfigPath, cached);
3009
+ }
3010
+ } catch {
3011
+ cached = defaultMeta;
3012
+ }
3013
+ metaByDir.set(dir, cached);
3014
+ }
3015
+ return cached;
3016
+ }
3017
+ function getTagLookupForProject(meta, dir) {
3018
+ const cache = meta.config.cache.get(getTagLookupForProject);
3019
+ let lookup = cache == null ? void 0 : cache.get(dir);
3020
+ if (lookup === void 0) {
3021
+ try {
3022
+ lookup = meta.compiler.taglib.buildLookup(
3023
+ dir,
3024
+ meta.config.translator,
3025
+ ignoreErrors
3026
+ );
3027
+ } catch {
3028
+ if (meta !== defaultMeta) {
3029
+ lookup = getTagLookupForProject(defaultMeta, dir);
3030
+ }
3031
+ }
3032
+ if (cache) {
3033
+ cache.set(dir, lookup);
3034
+ } else {
3035
+ meta.config.cache.set(getTagLookupForProject, /* @__PURE__ */ new Map([[dir, lookup]]));
3036
+ }
3037
+ }
3038
+ return lookup;
3039
+ }
3040
+ function clearCacheForMeta(meta) {
3041
+ meta.config.cache.clear();
3042
+ meta.compiler.taglib.clearCaches();
3043
+ }
3044
+ function tryParseJSONWithComments(content) {
3045
+ try {
3046
+ return JSON.parse(stripJSONComments(content));
3047
+ } catch {
3048
+ return void 0;
3049
+ }
3050
+ }
3051
+ function interopDefault(mod) {
3052
+ return mod.default || mod;
3053
+ }
3054
+
3055
+ // src/processors/index.ts
3056
+ var processors_exports = {};
3057
+ __export(processors_exports, {
3058
+ create: () => create,
3059
+ extensions: () => extensions,
3060
+ has: () => has
3061
+ });
3062
+
3063
+ // src/util/get-ext.ts
3064
+ function getExt(fileName) {
3065
+ const extIndex = fileName.lastIndexOf(".");
3066
+ if (extIndex !== -1)
3067
+ return fileName.slice(extIndex);
3068
+ }
3069
+
3070
+ // src/processors/marko.ts
3071
+ import path3 from "path";
3072
+ var marko_default = {
3073
+ extension: ".marko",
3074
+ create({ ts, host, configFile }) {
3075
+ const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : ts.sys.getCurrentDirectory();
3076
+ const defaultScriptLang = configFile && /tsconfig.json$/.test(configFile) ? "ts" /* ts */ : "js" /* js */;
3077
+ const runtimeTypes = getTypeLibs(currentDirectory, ts, host);
3078
+ const rootNames = [
3079
+ runtimeTypes.internalTypesFile,
3080
+ runtimeTypes.markoTypesFile
3081
+ ];
3082
+ if (runtimeTypes.markoRunTypesFile) {
3083
+ rootNames.push(runtimeTypes.markoRunTypesFile);
3084
+ }
3085
+ if (runtimeTypes.markoRunGeneratedTypesFile) {
3086
+ rootNames.push(runtimeTypes.markoRunGeneratedTypesFile);
3087
+ }
3088
+ return {
3089
+ getRootNames() {
3090
+ return rootNames;
3091
+ },
3092
+ getScriptExtension(fileName) {
3093
+ return getScriptLang(fileName, defaultScriptLang, ts, host) === "ts" /* ts */ ? ts.Extension.Ts : ts.Extension.Js;
3094
+ },
3095
+ getScriptKind(fileName) {
3096
+ return getScriptLang(fileName, defaultScriptLang, ts, host) === "ts" /* ts */ ? ts.ScriptKind.TS : ts.ScriptKind.JS;
3097
+ },
3098
+ extract(fileName, code) {
3099
+ const dir = path3.dirname(fileName);
3100
+ const parsed = parse(code, fileName);
3101
+ return extractScript({
3102
+ ts,
3103
+ parsed,
3104
+ lookup: getTagLookup(dir),
3105
+ scriptLang: getScriptLang(
3106
+ fileName,
3107
+ defaultScriptLang,
3108
+ ts,
3109
+ host
3110
+ ),
3111
+ runtimeTypesCode: runtimeTypes.markoTypesCode
3112
+ });
3113
+ },
3114
+ print({ extracted: { parsed } }) {
3115
+ const { code, map } = getCompiler(
3116
+ path3.dirname(parsed.filename)
3117
+ ).compileSync(parsed.code, parsed.filename, {
3118
+ output: "source",
3119
+ stripTypes: true,
3120
+ sourceMaps: true
3121
+ });
3122
+ return { code, map };
3123
+ },
3124
+ printTypes({ printer, typeChecker, sourceFile, formatSettings }) {
3125
+ var _a, _b, _c;
3126
+ let code = "";
3127
+ const nlChar = formatSettings.newLineCharacter;
3128
+ const tabChar = formatSettings.convertTabsToSpaces ? " ".repeat(formatSettings.indentSize) : " ";
3129
+ let defaultExport;
3130
+ let defaultExportId;
3131
+ let componentImpl;
3132
+ let internalRenderImpl;
3133
+ for (const statement of sourceFile.statements) {
3134
+ if (ts.isExportAssignment(statement)) {
3135
+ defaultExport = statement;
3136
+ defaultExportId = ts.isIdentifier(statement.expression) ? statement.expression.escapedText : void 0;
3137
+ } else if (ts.isClassDeclaration(statement) && ((_a = statement.name) == null ? void 0 : _a.escapedText) === "Component") {
3138
+ componentImpl = statement;
3139
+ } else if (ts.isFunctionDeclaration(statement) && ((_b = statement.name) == null ? void 0 : _b.escapedText) === "___marko_internal_template") {
3140
+ internalRenderImpl = statement;
3141
+ }
3142
+ }
3143
+ for (const statement of sourceFile.statements) {
3144
+ if (statement === defaultExport || // skips the generated `export default ...`.
3145
+ statement === componentImpl || // skips the generated `class {}` since it needs special processing.
3146
+ statement === internalRenderImpl || // skips the internal template render code.
3147
+ isExportComponentType(statement) || // skips the generated `export { type Component }`.
3148
+ isImportComponentType(statement) || // skips the generated `import type Component from "..."`.
3149
+ isExportEmptyInputType(statement) || // skips empty exported Input, eg `export type Input = {}` or `export interface Input {}`.
3150
+ isExportInputTypeAsComponentInput(statement) || // skips outputing `export type Input = Component["input"]` since it's inferred.
3151
+ defaultExportId && // If the `export default` was an identifier, we also remove the variable that declared the identifier.
3152
+ isVariableStatementForName(statement, defaultExportId)) {
3153
+ continue;
3154
+ }
3155
+ const printed = printer.printNode(
3156
+ ts.EmitHint.Unspecified,
3157
+ statement,
3158
+ sourceFile
3159
+ );
3160
+ if (!/^(?:import|export) /.test(printed))
3161
+ code += "static ";
3162
+ code += printed + nlChar;
3163
+ }
3164
+ if (componentImpl == null ? void 0 : componentImpl.members.length) {
3165
+ code += `class {${nlChar}`;
3166
+ for (const member of componentImpl.members) {
3167
+ if (ts.isPropertyDeclaration(member)) {
3168
+ code += `${tabChar}declare ${printer.printNode(ts.EmitHint.Unspecified, member, sourceFile) + nlChar}`;
3169
+ } else if (ts.isMethodDeclaration(member) || ts.isGetAccessorDeclaration(member) || ts.isSetAccessorDeclaration(member)) {
3170
+ code += `${tabChar + printer.printNode(ts.EmitHint.Unspecified, member, sourceFile).replace(/;\s*$/, "")} { return ${castType("any")}; }${nlChar}`;
3171
+ } else if (ts.isIndexSignatureDeclaration(member)) {
3172
+ code += tabChar + printer.printNode(ts.EmitHint.Unspecified, member, sourceFile) + nlChar;
3173
+ }
3174
+ }
3175
+ code += `}${nlChar}`;
3176
+ }
3177
+ if (internalRenderImpl) {
3178
+ const returnType = (_c = typeChecker.getSignatureFromDeclaration(internalRenderImpl)) == null ? void 0 : _c.getReturnType();
3179
+ if (returnType) {
3180
+ const props = returnType.getProperties();
3181
+ const valueType = props.length === 1 && props[0].name === "value" && typeChecker.getPropertyOfType(returnType, "value") || void 0;
3182
+ code += "<return ";
3183
+ if (valueType) {
3184
+ code += `= ${castType(
3185
+ typeChecker.typeToString(typeChecker.getTypeOfSymbol(valueType))
3186
+ )}`;
3187
+ } else {
3188
+ code += `...${castType(typeChecker.typeToString(returnType))}`;
3189
+ }
3190
+ code += `/>${nlChar}`;
3191
+ }
3192
+ }
3193
+ return { code };
3194
+ }
3195
+ };
3196
+ function isImportComponentType(statement) {
3197
+ var _a, _b;
3198
+ return ts.isImportDeclaration(statement) && ((_b = (_a = statement.importClause) == null ? void 0 : _a.name) == null ? void 0 : _b.escapedText) === "Component";
3199
+ }
3200
+ function isExportInputTypeAsComponentInput(statement) {
3201
+ return ts.isTypeAliasDeclaration(statement) && statement.name.escapedText === "Input" && ts.isIndexedAccessTypeNode(statement.type) && ts.isTypeReferenceNode(statement.type.objectType) && ts.isIdentifier(statement.type.objectType.typeName) && statement.type.objectType.typeName.escapedText === "Component" && ts.isLiteralTypeNode(statement.type.indexType) && ts.isStringLiteral(statement.type.indexType.literal) && statement.type.indexType.literal.text === "input";
3202
+ }
3203
+ function isExportEmptyInputType(statement) {
3204
+ return ts.isTypeAliasDeclaration(statement) && statement.name.escapedText === "Input" && ts.isTypeLiteralNode(statement.type) && !statement.typeParameters && statement.type.members.length === 0 || ts.isInterfaceDeclaration(statement) && statement.name.escapedText === "Input" && !statement.typeParameters && statement.members.length === 0;
3205
+ }
3206
+ function isExportComponentType(statement) {
3207
+ return ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause) && statement.exportClause.elements.length === 1 && statement.exportClause.elements[0].name.escapedText === "Component";
3208
+ }
3209
+ function isVariableStatementForName(statement, name) {
3210
+ if (ts.isVariableStatement(statement)) {
3211
+ for (const decl of statement.declarationList.declarations) {
3212
+ if (ts.isIdentifier(decl.name) && decl.name.escapedText === name) {
3213
+ return true;
3214
+ }
3215
+ }
3216
+ }
3217
+ }
3218
+ }
3219
+ };
3220
+ function castType(type) {
3221
+ if (type === "any") {
3222
+ return "1 as any";
3223
+ }
3224
+ return `(1 as any as ${type})`;
3225
+ }
3226
+
3227
+ // src/processors/index.ts
3228
+ var extensions = [marko_default.extension];
3229
+ function create(options) {
3230
+ return {
3231
+ [marko_default.extension]: marko_default.create(options)
3232
+ };
3233
+ }
3234
+ function has(fileName) {
3235
+ const ext = getExt(fileName);
3236
+ return !!(ext && extensions.includes(ext));
3237
+ }
3238
+
3239
+ // src/util/is-definition-file.ts
3240
+ function isDefinitionFile(fileName) {
3241
+ return /\.d\.[^.]+$/.test(fileName);
3242
+ }
2818
3243
  export {
2819
3244
  NodeType,
3245
+ processors_exports as Processors,
3246
+ project_exports as Project,
2820
3247
  ScriptLang,
2821
3248
  UNFINISHED,
2822
3249
  extractScript,
2823
3250
  extractStyle,
3251
+ getExt,
2824
3252
  getLines,
2825
3253
  getLocation,
2826
3254
  getPosition,
3255
+ isDefinitionFile,
2827
3256
  parse
2828
3257
  };
@@ -0,0 +1,36 @@
1
+ import type ts from "typescript/lib/tsserverlibrary";
2
+ import { Extracted } from "../util/extractor";
3
+ export type ProcessorExtension = `.${string}`;
4
+ export interface ProcessorConfig {
5
+ extension: ProcessorExtension;
6
+ create(options: CreateProcessorOptions): Processor;
7
+ }
8
+ export interface CreateProcessorOptions {
9
+ ts: typeof ts;
10
+ host: ts.ModuleResolutionHost;
11
+ configFile: string | undefined;
12
+ }
13
+ export interface Processor {
14
+ getRootNames?(): string[];
15
+ getScriptExtension(fileName: string): ts.Extension;
16
+ getScriptKind(fileName: string): ts.ScriptKind;
17
+ extract(fileName: string, code: string): Extracted;
18
+ print(context: PrintContext): {
19
+ code: string;
20
+ map?: any;
21
+ };
22
+ printTypes(context: PrintContext): {
23
+ code: string;
24
+ map?: any;
25
+ };
26
+ }
27
+ export interface PrintContext {
28
+ extracted: Extracted;
29
+ printer: ts.Printer;
30
+ sourceFile: ts.SourceFile;
31
+ typeChecker: ts.TypeChecker;
32
+ formatSettings: Required<ts.FormatCodeSettings>;
33
+ }
34
+ export declare const extensions: `.${string}`[];
35
+ export declare function create(options: Parameters<ProcessorConfig["create"]>[0]): Record<`.${string}`, Processor>;
36
+ export declare function has(fileName: string): boolean;
@@ -0,0 +1,18 @@
1
+ import type ts from "typescript/lib/tsserverlibrary";
2
+ declare const _default: {
3
+ extension: ".marko";
4
+ create({ ts, host, configFile }: import(".").CreateProcessorOptions): {
5
+ getRootNames(): string[];
6
+ getScriptExtension(fileName: string): ts.Extension.Ts | ts.Extension.Js;
7
+ getScriptKind(fileName: string): ts.ScriptKind.JS | ts.ScriptKind.TS;
8
+ extract(fileName: string, code: string): import("..").Extracted;
9
+ print({ extracted: { parsed } }: import(".").PrintContext): {
10
+ code: string;
11
+ map: import("magic-string").SourceMap;
12
+ };
13
+ printTypes({ printer, typeChecker, sourceFile, formatSettings }: import(".").PrintContext): {
14
+ code: string;
15
+ };
16
+ };
17
+ };
18
+ export default _default;
@@ -16,6 +16,7 @@ export declare class Extractor {
16
16
  }
17
17
  export declare class Extracted {
18
18
  #private;
19
+ parsed: Parsed;
19
20
  constructor(parsed: Parsed, generated: string, tokens: Token[]);
20
21
  sourceOffsetAt(generatedOffset: number): number | undefined;
21
22
  sourcePositionAt(generatedOffset: number): Position | undefined;
@@ -0,0 +1 @@
1
+ export declare function getExt(fileName: string): `.${string}` | undefined;
@@ -0,0 +1 @@
1
+ export declare function isDefinitionFile(fileName: string): boolean;
@@ -0,0 +1,68 @@
1
+ /// <reference types="node" />
2
+ import type TS from "typescript/lib/tsserverlibrary";
3
+ import type { TaglibLookup } from "@marko/babel-utils";
4
+ import * as defaultCompiler from "@marko/compiler";
5
+ import { ScriptLang } from "../extractors/script";
6
+ export interface Meta {
7
+ compiler: typeof defaultCompiler;
8
+ config: Omit<defaultCompiler.Config, "cache" | "translator"> & {
9
+ cache: Map<any, any>;
10
+ translator: {
11
+ runtimeTypes?: string;
12
+ [x: string]: unknown;
13
+ };
14
+ };
15
+ }
16
+ export declare function getCompiler(dir?: string): typeof defaultCompiler;
17
+ export declare function getCache(dir?: string): Map<any, any>;
18
+ export declare function getConfig(dir?: string): Omit<{
19
+ output?: "source" | "html" | "dom" | "hydrate" | "migrate" | undefined;
20
+ stripTypes?: boolean | undefined;
21
+ runtimeId?: string | null | undefined;
22
+ ast?: boolean | undefined;
23
+ code?: boolean | undefined;
24
+ writeVersionComment?: boolean | undefined;
25
+ ignoreUnrecognizedTags?: boolean | undefined;
26
+ sourceMaps?: boolean | "inline" | "both" | undefined;
27
+ translator?: any;
28
+ fileSystem?: typeof import("fs") | undefined;
29
+ modules?: "esm" | "cjs" | undefined;
30
+ resolveVirtualDependency?: ((filename: string, dep: {
31
+ virtualPath: string;
32
+ code: string;
33
+ map?: any;
34
+ }) => string) | null | undefined;
35
+ hydrateIncludeImports?: RegExp | ((request: string) => boolean) | undefined;
36
+ optimize?: boolean | undefined;
37
+ cache?: Map<unknown, unknown> | undefined;
38
+ hot?: boolean | undefined;
39
+ meta?: boolean | undefined;
40
+ babelConfig?: {
41
+ [x: string]: unknown;
42
+ ast?: boolean | null | undefined;
43
+ code?: boolean | null | undefined;
44
+ comments?: boolean | null | undefined;
45
+ compact?: boolean | "auto" | null | undefined;
46
+ caller?: {
47
+ [x: string]: unknown;
48
+ name?: string | undefined;
49
+ } | undefined;
50
+ minified?: boolean | null | undefined;
51
+ } | undefined;
52
+ }, "cache" | "translator"> & {
53
+ cache: Map<any, any>;
54
+ translator: {
55
+ [x: string]: unknown;
56
+ runtimeTypes?: string | undefined;
57
+ };
58
+ };
59
+ export declare function getTagLookup(dir: string): TaglibLookup;
60
+ export declare function getTypeLibs(rootDir: string, ts: typeof TS, host: TS.ModuleResolutionHost): {
61
+ internalTypesFile: string;
62
+ markoRunTypesFile: string | undefined;
63
+ markoRunGeneratedTypesFile: string | undefined;
64
+ markoTypesFile: string;
65
+ markoTypesCode: string;
66
+ };
67
+ export declare function getScriptLang(fileName: string, defaultScriptLang: ScriptLang, ts: typeof TS, host: TS.ModuleResolutionHost): ScriptLang;
68
+ export declare function clearCaches(): void;
package/package.json CHANGED
@@ -1,23 +1,25 @@
1
1
  {
2
2
  "name": "@marko/language-tools",
3
3
  "description": "Marko Language Tools",
4
- "version": "1.0.2",
4
+ "version": "2.0.0",
5
5
  "bugs": "https://github.com/marko-js/language-server/issues/new?template=Bug_report.md",
6
6
  "dependencies": {
7
7
  "@babel/helper-validator-identifier": "^7.19.1",
8
8
  "@babel/parser": "^7.21.3",
9
+ "@marko/compiler": "5.27.4",
10
+ "@marko/translator-default": "5.25.4",
9
11
  "htmljs-parser": "^5.4.3",
10
12
  "relative-import-path": "^1.0.0"
11
13
  },
12
14
  "devDependencies": {
13
15
  "@babel/code-frame": "^7.18.6",
14
- "@marko/compiler": "^5.27.1",
16
+ "@marko/compiler": "^5.27.4",
15
17
  "@types/babel__code-frame": "^7.0.3",
16
18
  "@types/babel__helper-validator-identifier": "^7.15.0",
17
19
  "@typescript/vfs": "^1.4.0",
18
- "marko": "^5.25.1",
20
+ "marko": "^5.25.4",
19
21
  "mitata": "^0.1.6",
20
- "tsx": "^3.12.5"
22
+ "tsx": "^3.12.6"
21
23
  },
22
24
  "exports": {
23
25
  ".": {