summaryrefslogtreecommitdiff
path: root/js/type_directives.ts
diff options
context:
space:
mode:
Diffstat (limited to 'js/type_directives.ts')
-rw-r--r--js/type_directives.ts87
1 files changed, 87 insertions, 0 deletions
diff --git a/js/type_directives.ts b/js/type_directives.ts
new file mode 100644
index 000000000..3e903a80b
--- /dev/null
+++ b/js/type_directives.ts
@@ -0,0 +1,87 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+
+interface DirectiveInfo {
+ path: string;
+ start: number;
+ end: number;
+}
+
+/** Remap the module name based on any supplied type directives passed. */
+export function getMappedModuleName(
+ moduleName: string,
+ containingFile: string,
+ typeDirectives?: Record<string, string>
+): string {
+ if (containingFile.endsWith(".d.ts") && !moduleName.endsWith(".d.ts")) {
+ moduleName = `${moduleName}.d.ts`;
+ }
+ if (!typeDirectives) {
+ return moduleName;
+ }
+ if (moduleName in typeDirectives) {
+ return typeDirectives[moduleName];
+ }
+ return moduleName;
+}
+
+/** Matches directives that look something like this and parses out the value
+ * of the directive:
+ *
+ * // @deno-types="./foo.d.ts"
+ *
+ * [See Diagram](http://bit.ly/31nZPCF)
+ */
+const typeDirectiveRegEx = /@deno-types\s*=\s*(["'])((?:(?=(\\?))\3.)*?)\1/gi;
+
+/** Matches `import` or `export from` statements and parses out the value of the
+ * module specifier in the second capture group:
+ *
+ * import * as foo from "./foo.js"
+ * export { a, b, c } from "./bar.js"
+ *
+ * [See Diagram](http://bit.ly/2GSkJlF)
+ */
+const importExportRegEx = /(?:import|export)\s+[\s\S]*?from\s+(["'])((?:(?=(\\?))\3.)*?)\1/;
+
+/** Parses out any Deno type directives that are part of the source code, or
+ * returns `undefined` if there are not any.
+ */
+export function parseTypeDirectives(
+ sourceCode: string | undefined
+): Record<string, string> | undefined {
+ if (!sourceCode) {
+ return;
+ }
+
+ // collect all the directives in the file and their start and end positions
+ const directives: DirectiveInfo[] = [];
+ let maybeMatch: RegExpExecArray | null = null;
+ while ((maybeMatch = typeDirectiveRegEx.exec(sourceCode))) {
+ const [matchString, , path] = maybeMatch;
+ const { index: start } = maybeMatch;
+ directives.push({
+ path,
+ start,
+ end: start + matchString.length
+ });
+ }
+ if (!directives.length) {
+ return;
+ }
+
+ // work from the last directive backwards for the next `import`/`export`
+ // statement
+ directives.reverse();
+ const directiveRecords: Record<string, string> = {};
+ for (const { path, start, end } of directives) {
+ const searchString = sourceCode.substring(end);
+ const maybeMatch = importExportRegEx.exec(searchString);
+ if (maybeMatch) {
+ const [, , fromPath] = maybeMatch;
+ directiveRecords[fromPath] = path;
+ }
+ sourceCode = sourceCode.substring(0, start);
+ }
+
+ return directiveRecords;
+}