UNPKG

jsii

Version:

[![Join the chat at https://cdk.Dev](https://img.shields.io/static/v1?label=Slack&message=cdk.dev&color=brightgreen&logo=slack)](https://cdk.dev) [![Build Status](https://github.com/aws/jsii-compiler/workflows/build/badge.svg)](https://github.com/aws/jsii

198 lines • 7.69 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.symbolIdentifier = symbolIdentifier; exports.normalizePath = normalizePath; const fs = __importStar(require("node:fs")); const path = __importStar(require("node:path")); const ts = __importStar(require("typescript")); const find_utils_1 = require("./find-utils"); /** * Return a symbol identifier for the given symbol * * The symbol identifier identifies a TypeScript symbol in a source file inside * a package. We can use this to map between jsii entries in the manifest, and * entities in the TypeScript source code. * * Going via symbol id is the only way to identify symbols in submodules. Otherwise, * all the TypeScript compiler sees is: * * ``` * /my/package/lib/source/directory/dist.js <containing> MyClass * ``` * * And there's no way to figure out what submodule name * `lib/source/directory/dist` is exported as. * * The format of a symbol id is: * * ``` * relative/source/file:Name.space.Class[#member] * ``` * * We used to build this identifier ourselves. Turns out there was a built-in * way to get pretty much the same, by calling `typeChecker.getFullyQualifiedName()`. * Whoops ^_^ (this historical accident is why the format is similar to but * different from what the TS checker returns). */ function symbolIdentifier(typeChecker, sym, options = {}) { if (!sym) { return undefined; } // If this symbol happens to be an alias, resolve it first // eslint-disable-next-line no-bitwise while ((sym.flags & ts.SymbolFlags.Alias) !== 0) { sym = typeChecker.getAliasedSymbol(sym); } const isMember = // eslint-disable-next-line no-bitwise (sym.flags & // eslint-disable-next-line no-bitwise (ts.SymbolFlags.Method | // eslint-disable-next-line no-bitwise ts.SymbolFlags.Property | ts.SymbolFlags.EnumMember)) !== 0; const tsName = typeChecker.getFullyQualifiedName(sym); // TypeScript fqn looks like "/path/to/file"[.name.in.file] const groups = /^"([^"]+)"(?:\.(.*))?$/.exec(tsName); if (!groups) { return undefined; } const [, fileName, inFileName] = groups; // inFileName may be absent const relFile = Helper.for(typeChecker).assemblyRelativeSourceFile(fileName, options?.assembly); if (!relFile) { return undefined; } // If this is a member symbol, replace the final '.' with a '#' const typeSymbol = isMember ? (inFileName ?? '').replace(/\.([^.]+)$/, '#$1') : inFileName ?? ''; return `${relFile}:${typeSymbol}`; } class Helper { static for(typeChecker) { const cached = this.INSTANCES.get(typeChecker); if (cached != null) { return cached; } const helper = new Helper(); this.INSTANCES.set(typeChecker, helper); return helper; } static INSTANCES = new WeakMap(); packageInfo = new Map(); constructor() { } assemblyRelativeSourceFile(sourceFileName, asm) { const packageInfo = this.findPackageInfo(path.dirname(sourceFileName)); if (!packageInfo) { return undefined; } let sourcePath = removePrefix(packageInfo.outdir ?? '', path.relative(packageInfo.packageJsonDir, sourceFileName)); // Modify the namespace if we send in the assembly. if (asm) { const tscRootDir = packageInfo.tscRootDir ?? asm.metadata?.tscRootDir; const tscOutDir = packageInfo.tscOutDir; sourcePath = normalizePath(sourcePath, tscRootDir, tscOutDir); } return sourcePath.replace(/(\.d)?\.ts$/, ''); function removePrefix(prefix, filePath) { const prefixParts = prefix.split(/[/\\]/g); const pathParts = filePath.split(/[/\\]/g); let i = 0; while (prefixParts[i] === pathParts[i]) { i++; } return pathParts.slice(i).join('/'); } } findPackageInfo(from) { if (this.packageInfo.has(from)) { return this.packageInfo.get(from); } const packageJsonDir = (0, find_utils_1.findUp)(from, (dir) => fs.existsSync(path.join(dir, 'package.json'))); if (!packageJsonDir) { this.packageInfo.set(from, undefined); return undefined; } if (this.packageInfo.has(packageJsonDir)) { return this.packageInfo.get(packageJsonDir); } const { jsii } = JSON.parse(fs.readFileSync(path.join(packageJsonDir, 'package.json'), 'utf-8')); const result = { packageJsonDir, outdir: jsii?.outdir, tscRootDir: jsii?.tsc?.rootDir, tscOutDir: jsii?.tsc?.outDir, }; this.packageInfo.set(from, result); this.packageInfo.set(packageJsonDir, result); return result; } } /** * Ensures that the sourcePath is pointing to the source code * and not compiled code. This can happen if the root directory * and/or out directory is set for the project. We check to see * if the out directory is present in the sourcePath, and if so, * we replace it with the root directory. */ function normalizePath(sourcePath, rootDir, outDir) { if (rootDir === undefined || outDir === undefined) { return sourcePath; } outDir = removeEndSlash(path.normalize(outDir)); const outDirLength = outDir.split(path.sep).length; rootDir = removeEndSlash(path.normalize(rootDir)); let paths = path.normalize(sourcePath).split(path.sep); const pathDir = paths.slice(0, outDirLength).join(path.sep); if (outDir === pathDir || outDir === '.') { // outDir === '.' is a special case where we do not want // to remove any paths from the list. if (outDir !== '.') { paths = paths.slice(outDirLength); } sourcePath = rootDir === '.' ? paths.join('/') : `${rootDir}/${paths.join('/')}`; } return unixize(sourcePath); function removeEndSlash(filePath) { return filePath.endsWith(path.sep) ? filePath.slice(0, filePath.length - 1) : filePath; } } /** * Turn backslashes in a path into forward slashes */ function unixize(p) { return p.replace(/\\/g, '/'); } //# sourceMappingURL=symbol-id.js.map