diff options
author | 2021-05-15 17:23:55 -0700 | |
---|---|---|
committer | 2021-05-15 17:23:55 -0700 | |
commit | e80f865974df7aae5e2f6abb966b36497da693c6 (patch) | |
tree | e82bcf4860c1fc43de189f13a18e8526a2966f44 | |
parent | c88625436cf866bdaa68249d10880a2271f611e0 (diff) | |
download | bun-e80f865974df7aae5e2f6abb966b36497da693c6.tar.gz bun-e80f865974df7aae5e2f6abb966b36497da693c6.tar.zst bun-e80f865974df7aae5e2f6abb966b36497da693c6.zip |
lots
Former-commit-id: d8b1d296562a01800248bd1148bc4778225b436e
-rw-r--r-- | .gitignore | 8 | ||||
-rw-r--r-- | .vscode/launch.json | 44 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | build.zig | 31 | ||||
-rw-r--r-- | out.txt | 318 | ||||
-rw-r--r-- | outdir/index.css | 113 | ||||
-rw-r--r-- | outdir/index.js | 2338 | ||||
-rw-r--r-- | src/api/demo/pages/index.jsx (renamed from src/api/demo/pages/index.js) | 0 | ||||
-rw-r--r-- | src/bundler.zig | 4 | ||||
-rw-r--r-- | src/cli.zig | 18 | ||||
-rw-r--r-- | src/fs.zig | 2 | ||||
-rw-r--r-- | src/hash_map_v2.zig | 1818 | ||||
-rw-r--r-- | src/js_ast.zig | 8 | ||||
-rw-r--r-- | src/js_lexer.zig | 21 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 295 | ||||
-rw-r--r-- | src/js_parser/js_parser_test.zig | 14 | ||||
-rw-r--r-- | src/js_printer.zig | 4 | ||||
-rw-r--r-- | src/json_parser.zig | 31 | ||||
-rw-r--r-- | src/logger.zig | 2 | ||||
-rw-r--r-- | src/options.zig | 12 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 262 | ||||
-rw-r--r-- | src/test/fixtures/cannot-assign-to-import-bug.js | 369 | ||||
-rw-r--r-- | src/test/fixtures/img-bug.js | 105 | ||||
-rw-r--r-- | src/test/fixtures/react-dev-crash.js | 108 |
24 files changed, 5623 insertions, 310 deletions
diff --git a/.gitignore b/.gitignore index 3b7ab51c0..0b9af8f8d 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,10 @@ src/deps/zig-clap/example src/deps/zig-clap/README.md src/deps/zig-clap/.github src/deps/zig-clap/.gitattributes -out
\ No newline at end of file +out + +.trace +cover +coverage +coverv +*.trace
\ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index db273b198..ac77daf98 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -15,40 +15,58 @@ // "type": "lldb", // "request": "launch", // "name": "Dev Launch", - // "program": "${workspaceFolder}/build/bin/debug/esdev", + // "program": "${workspaceFolder}/build/debug/macos-x86_64/esdev", // "preLaunchTask": "build", // "args": [ - // "--resolve=dev", + // "--resolve=disable", // "--cwd", - // "./src/api/demo", - // "pages/index.js", + // "${workspaceFolder}", + // "src/test/fixtures/cannot-assign-to-import-bug.js", // "-o", // "out" // ], // "cwd": "${workspaceFolder}", // "console": "internalConsole" // } + { "type": "lldb", "request": "launch", "name": "Dev Launch", - "program": "${workspaceFolder}/build/bin/debug/esdev", + "program": "${workspaceFolder}/build/debug/macos-x86_64/esdev", "preLaunchTask": "build", "args": [ "--resolve=dev", "--cwd", - "/", - "/Users/jarredsumner/Code/esdev/src/test/fixtures/img-bug.js", + "./src/api/demo", + "pages/index.js", "-o", "out" ], "cwd": "${workspaceFolder}", - "console": "internalConsole", - "presentation": { - "hidden": false, - "group": "", - "order": 1 - } + "console": "internalConsole" } + // { + // "type": "lldb", + // "request": "launch", + // "name": "Dev Launch", + // "program": "${workspaceFolder}/build/bin/debug/esdev", + // "preLaunchTask": "build", + // "args": [ + // "--resolve=dev", + // "--cwd", + // "/", + // "/Users/jarredsumner/Code/esdev/src/test/fixtures/img-bug.js", + // "-o", + // "out" + // ], + // "cwd": "${workspaceFolder}", + // "console": "internalConsole", + // "presentation": { + // "hidden": false, + // "group": "", + // "order": 1 + // } + // } ] } @@ -4,8 +4,12 @@ speedy: speedy-prod-native speedy-prod-wasi speedy-prod-wasm api: peechy --schema src/api/schema.peechy --esm src/api/schema.js --ts src/api/schema.d.ts --zig src/api/schema.zig -speedy-prod-native: - zig build -Drelease-fast + +speedy-prod-native-macos: + zig build -Drelease-fast -Dtarget=x86_64-macos-gnu + +speedy-m1: + zig build -Drelease-fast -Dtarget=aarch64-macos-gnu speedy-prod-wasm: zig build -Drelease-fast -Dtarget=wasm32-freestanding @@ -15,20 +15,16 @@ pub fn build(b: *std.build.Builder) void { var cwd = std.os.getcwd(&cwd_buf) catch unreachable; var exe: *std.build.LibExeObjStep = undefined; - std.debug.print("Build Mode: {s}\n", .{@tagName(mode)}); + var output_dir_buf = std.mem.zeroes([4096]u8); + var bin_label = if (mode == std.builtin.Mode.Debug) "/debug/" else "/"; + const output_dir = std.fmt.bufPrint(&output_dir_buf, "build{s}{s}-{s}", .{ bin_label, @tagName(target.getOs().tag), @tagName(target.getCpuArch()) }) catch unreachable; if (target.getOsTag() == .wasi) { - std.debug.print("Build OS: Wasi\n", .{}); exe.enable_wasmtime = true; exe = b.addExecutable("esdev", "src/main_wasi.zig"); exe.is_dynamic = true; - if (mode == std.builtin.Mode.Debug) { - exe.setOutputDir("build/wasi/debug"); - } else { - exe.setOutputDir("build/wasi"); - } + exe.setOutputDir(output_dir); } else if (target.getCpuArch().isWasm()) { - std.debug.print("Build OS: WASM\n", .{}); // exe = b.addExecutable( // "esdev", // "src/main_wasm.zig", @@ -45,17 +41,15 @@ pub fn build(b: *std.build.Builder) void { var features = target.getCpuFeatures(); features.addFeature(2); target.updateCpuFeatures(&features); - lib.setOutputDir("build/wasm/debug"); } else { // lib.strip = true; - lib.setOutputDir("build/wasm"); } + lib.setOutputDir(output_dir); lib.want_lto = true; b.install_path = lib.getOutputPath(); - std.debug.print("Build Destination: {s}\n", .{lib.getOutputPath()}); - + std.debug.print("Build: ./{s}\n", .{lib.getOutputPath()}); b.default_step.dependOn(&lib.step); b.verbose_link = true; lib.setTarget(target); @@ -77,15 +71,8 @@ pub fn build(b: *std.build.Builder) void { return; } else { - std.debug.print("Build OS: Native\n", .{}); exe = b.addExecutable("esdev", "src/main.zig"); exe.linkLibC(); - - if (mode == std.builtin.Mode.Debug) { - exe.setOutputDir("build/bin/debug"); - } else { - exe.setOutputDir("build/bin"); - } } exe.addPackage(.{ @@ -93,7 +80,8 @@ pub fn build(b: *std.build.Builder) void { .path = "src/deps/zig-clap/clap.zig", }); - std.debug.print("Build Destination: {s}\n", .{exe.getOutputPath()}); + exe.setOutputDir(output_dir); + std.debug.print("Build: ./{s}\n", .{exe.getOutputPath()}); var walker = std.fs.walkPath(std.heap.page_allocator, cwd) catch unreachable; if (std.builtin.is_test) { while (walker.next() catch unreachable) |entry| { @@ -105,9 +93,8 @@ pub fn build(b: *std.build.Builder) void { } exe.setTarget(target); exe.setBuildMode(mode); - b.install_path = exe.getOutputPath(); + b.install_path = output_dir; - std.fs.deleteTreeAbsolute(std.fs.path.join(std.heap.page_allocator, &.{ cwd, exe.getOutputPath() }) catch unreachable) catch {}; if (!target.getCpuArch().isWasm()) { exe.addLibPath("/usr/local/lib"); } diff --git a/out.txt b/out.txt new file mode 100644 index 000000000..5a6bd56af --- /dev/null +++ b/out.txt @@ -0,0 +1,318 @@ +/Users/jarredsumner/Code/esdev: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo/.: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo/./pages/..: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/.: readFile error -- IsDir/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/.: readFile error -- IsDir + +error: Cannot read file "/Users/jarredsumner/Code/esdev": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo/.": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo/./pages/..": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/.": IsDir + + + +error: Cannot read file "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/.": IsDir + + + +error: Cannot assign to property on import "newObj" +"use strict";exports.__esModule=true;exports.defaultHead=defaultHead;exports.default=void 0;var _react=_interopRequireWildcard(require("react"));var _sideEffect=_interopRequireDefault(require("./side-effect"));var _ampContext=require("./amp-context");var _headManagerContext=require("./head-manager-context");var _amp=require("./amp");function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}function _getRequireWildcardCache(){if(typeof WeakMap!=="function")return null;var cache=new WeakMap();_getRequireWildcardCache=function(){return cache;};return cache;}function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}if(obj===null||typeof obj!=="object"&&typeof obj!=="function"){return{default:obj};}var cache=_getRequireWildcardCache();if(cache&&cache.has(obj)){return cache.get(obj);}var newObj={};var hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;if(desc&&(desc.get||desc.set)){Object.defineProperty(newObj,key,desc);}else{newObj[key]=obj[key];}}}newObj.default=obj;if(cache){cache.set(obj,newObj);}return newObj;}function defaultHead(inAmpMode=false){const head=[/*#__PURE__*/_react.default.createElement("meta",{charSet:"utf-8"})];if(!inAmpMode){head.push(/*#__PURE__*/_react.default.createElement("meta",{name:"viewport",content:"width=device-width"}));}return head;}function onlyReactElement(list,child){// React children can be "string" or "number" in this case we ignore them for backwards compat + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/next-server/lib/head.js:1:1149 1148 + + +error: Cannot assign to property on import "metaCategories" +switch(h.type){case'title':case'base':if(tags.has(h.type)){isUnique=false;}else{tags.add(h.type);}break;case'meta':for(let i=0,len=METATYPES.length;i<len;i++){const metatype=METATYPES[i];if(!h.props.hasOwnProperty(metatype))continue;if(metatype==='charSet'){if(metaTypes.has(metatype)){isUnique=false;}else{metaTypes.add(metatype);}}else{const category=h.props[metatype];const categories=metaCategories[metatype]||new Set();if((metatype!=='name'||!hasKey)&&categories.has(category)){isUnique=false;}else{categories.add(category);metaCategories[metatype]=categories;}}}break;}return isUnique;};}/** + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/next-server/lib/head.js:8:530 3158 + + +error: Cannot assign to property on import "newProps" +['https://fonts.googleapis.com/css'].some(url=>c.props['href'].startsWith(url))){const newProps={...(c.props||{})};newProps['data-href']=newProps['href'];newProps['href']=undefined;return/*#__PURE__*/_react.default.cloneElement(c,newProps);}}return/*#__PURE__*/_react.default.cloneElement(c,{key});});}/** + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/next-server/lib/head.js:12:116 3986 + + +error: Cannot assign to property on import "newProps" +['https://fonts.googleapis.com/css'].some(url=>c.props['href'].startsWith(url))){const newProps={...(c.props||{})};newProps['data-href']=newProps['href'];newProps['href']=undefined;return/*#__PURE__*/_react.default.cloneElement(c,newProps);}}return/*#__PURE__*/_react.default.cloneElement(c,{key});});}/** + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/next-server/lib/head.js:12:155 4025 + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./node_modules/@babel": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/node_modules/@babel": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/@babel/runtime": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/node_modules/@babel/runtime": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/node_modules/@babel/runtime": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/node_modules/@babel/runtime/helpers": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./node_modules/react": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/node_modules/react": FileNotFound + + + +error: Expected ")" but found , +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:89 2171 + + +error: Expected ";" but found ) +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:120 2202 + + +error: Expected ")" but found , +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:338 2420 + + +error: Expected ";" but found ) +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:340 2422 + + +error: Cannot assign to property on import "d" +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:157 2239 + + +error: Cannot assign to property on import "f" +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:259 2341 + + +error: Cannot assign to property on import "d" +function J(a,b,c){var e,d={},k=null,h=null;if(null!=b)for(e in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(k=""+b.key),b)H.call(b,e)&&!I.hasOwnProperty(e)&&(d[e]=b[e]);var g=arguments.length-2;if(1===g)d.children=c;else if(1<g){for(var f=Array(g),m=0;m<g;m++)f[m]=arguments[m+2];d.children=f}if(a&&a.defaultProps)for(e in g=a.defaultProps,g)void 0===d[e]&&(d[e]=g[e]);return{$$typeof:n,type:a,key:k,ref:h,props:d,_owner:G.current}} + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:14:357 2439 + + +error: Cannot assign to property on import "e" +exports.cloneElement=function(a,b,c){if(null===a||void 0===a)throw Error(z(267,a));var e=l({},a.props),d=a.key,k=a.ref,h=a._owner;if(null!=b){void 0!==b.ref&&(k=b.ref,h=G.current);void 0!==b.key&&(d=""+b.key);if(a.type&&a.type.defaultProps)var g=a.type.defaultProps;for(f in b)H.call(b,f)&&!I.hasOwnProperty(f)&&(e[f]=void 0===b[f]&&void 0!==g?g[f]:b[f])}var f=arguments.length-2;if(1===f)e.children=c;else if(1<f){g=Array(f);for(var m=0;m<f;m++)g[m]=arguments[m+2];e.children=g}return{$$typeof:n,type:a.type, + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:20:314 4973 + + +error: Cannot assign to property on import "g" +exports.cloneElement=function(a,b,c){if(null===a||void 0===a)throw Error(z(267,a));var e=l({},a.props),d=a.key,k=a.ref,h=a._owner;if(null!=b){void 0!==b.ref&&(k=b.ref,h=G.current);void 0!==b.key&&(d=""+b.key);if(a.type&&a.type.defaultProps)var g=a.type.defaultProps;for(f in b)H.call(b,f)&&!I.hasOwnProperty(f)&&(e[f]=void 0===b[f]&&void 0!==g?g[f]:b[f])}var f=arguments.length-2;if(1===f)e.children=c;else if(1<f){g=Array(f);for(var m=0;m<f;m++)g[m]=arguments[m+2];e.children=g}return{$$typeof:n,type:a.type, + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.production.min.js:20:447 5106 + + +error: Cannot assign to property on import "args" + args[_key - 1] = arguments[_key]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:184:7 5256 + + +error: Cannot assign to property on import "args" + args[_key2 - 1] = arguments[_key2]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:193:7 5499 + + +error: Cannot assign to property on import "didWarnStateUpdateForUnmountedComponent" + didWarnStateUpdateForUnmountedComponent[warningKey] = true; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:238:5 7144 + + +error: Cannot assign to property on import "didWarnAboutStringRefs" + didWarnAboutStringRefs[componentName] = true; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:622:9 19312 + + +error: Cannot assign to property on import "props" + props[propName] = config[propName]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:734:9 22825 + + +error: Cannot assign to property on import "childArray" + childArray[i] = arguments[i + 2]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:749:7 23234 + + +error: Cannot assign to property on import "props" + props[propName] = defaultProps[propName]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:767:9 23588 + + +error: Cannot assign to property on import "props" + props[propName] = defaultProps[propName]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:842:11 25862 + + +error: Cannot assign to property on import "props" + props[propName] = config[propName]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:844:11 25931 + + +error: Cannot assign to property on import "childArray" + childArray[i] = arguments[i + 2]; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:860:7 26350 + + +error: Cannot use "break" here + break; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:1790:11 55454 + + +error: Cannot assign to property on import "loggedTypeFailures" + loggedTypeFailures[error$1.message] = true; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:1932:11 60269 + + +error: Cannot assign to property on import "ownerHasKeyUseWarning" + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; // Usually the current owner is the offender, but if it accepts children as a + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:2038:3 62986 + + +error: Cannot use "break" here + break; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./cjs/react.development.js:2169:9 67164 + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/./node_modules/object-assign": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/react/node_modules/object-assign": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/object-assign": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/src/api/demo/node_modules/object-assign": FileNotFound + + + +error: Cannot read directory "/Users/jarredsumner/Code/esdev/node_modules/object-assign": FileNotFound + + + +error: Unexpected "super" +"use strict";exports.__esModule=true;exports.default=void 0;var _react=require("react");const isServer=typeof window==='undefined';class _default extends _react.Component{constructor(props){super(props);this._hasHeadManager=void 0;this.emitChange=()=>{if(this._hasHeadManager){this.props.headManager.updateHead(this.props.reduceComponentsToState([...this.props.headManager.mountedInstances],this.props));}};this._hasHeadManager=this.props.headManager&&this.props.headManager.mountedInstances;if(isServer&&this._hasHeadManager){this.props.headManager.mountedInstances.add(this);this.emitChange();}}componentDidMount(){if(this._hasHeadManager){this.props.headManager.mountedInstances.add(this);}this.emitChange();}componentDidUpdate(){this.emitChange();}componentWillUnmount(){if(this._hasHeadManager){this.props.headManager.mountedInstances.delete(this);}this.emitChange();}render(){return null;}}exports.default=_default; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/next-server/lib/./side-effect.js:1:191 190 + + +error: Cannot assign to property on import "newObj" +"use strict";exports.__esModule=true;exports.defaultHead=defaultHead;exports.default=void 0;var _react=_interopRequireWildcard(require("react"));var _sideEffect=_interopRequireDefault(require("./side-effect"));var _ampContext=require("./amp-context");var _headManagerContext=require("./head-manager-context");var _amp=require("./amp");function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};}function _getRequireWildcardCache(){if(typeof WeakMap!=="function")return null;var cache=new WeakMap();_getRequireWildcardCache=function(){return cache;};return cache;}function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}if(obj===null||typeof obj!=="object"&&typeof obj!=="function"){return{default:obj};}var cache=_getRequireWildcardCache();if(cache&&cache.has(obj)){return cache.get(obj);}var newObj={};var hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;if(desc&&(desc.get||desc.set)){Object.defineProperty(newObj,key,desc);}else{newObj[key]=obj[key];}}}newObj.default=obj;if(cache){cache.set(obj,newObj);}return newObj;}function defaultHead(inAmpMode=false){const head=[/*#__PURE__*/_react.default.createElement("meta",{charSet:"utf-8"})];if(!inAmpMode){head.push(/*#__PURE__*/_react.default.createElement("meta",{name:"viewport",content:"width=device-width"}));}return head;}function onlyReactElement(list,child){// React children can be "string" or "number" in this case we ignore them for backwards compat + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/client/../next-server/lib/head.js:1:1149 1148 + + +error: Cannot assign to property on import "metaCategories" +switch(h.type){case'title':case'base':if(tags.has(h.type)){isUnique=false;}else{tags.add(h.type);}break;case'meta':for(let i=0,len=METATYPES.length;i<len;i++){const metatype=METATYPES[i];if(!h.props.hasOwnProperty(metatype))continue;if(metatype==='charSet'){if(metaTypes.has(metatype)){isUnique=false;}else{metaTypes.add(metatype);}}else{const category=h.props[metatype];const categories=metaCategories[metatype]||new Set();if((metatype!=='name'||!hasKey)&&categories.has(category)){isUnique=false;}else{categories.add(category);metaCategories[metatype]=categories;}}}break;}return isUnique;};}/** + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/client/../next-server/lib/head.js:8:530 3158 + + +error: Cannot assign to property on import "newProps" +['https://fonts.googleapis.com/css'].some(url=>c.props['href'].startsWith(url))){const newProps={...(c.props||{})};newProps['data-href']=newProps['href'];newProps['href']=undefined;return/*#__PURE__*/_react.default.cloneElement(c,newProps);}}return/*#__PURE__*/_react.default.cloneElement(c,{key});});}/** + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/client/../next-server/lib/head.js:12:116 3986 + + +error: Cannot assign to property on import "newProps" +['https://fonts.googleapis.com/css'].some(url=>c.props['href'].startsWith(url))){const newProps={...(c.props||{})};newProps['data-href']=newProps['href'];newProps['href']=undefined;return/*#__PURE__*/_react.default.cloneElement(c,newProps);}}return/*#__PURE__*/_react.default.cloneElement(c,{key});});}/** + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/client/../next-server/lib/head.js:12:155 4025 + + +error: Unexpected "super" +"use strict";exports.__esModule=true;exports.default=void 0;var _react=require("react");const isServer=typeof window==='undefined';class _default extends _react.Component{constructor(props){super(props);this._hasHeadManager=void 0;this.emitChange=()=>{if(this._hasHeadManager){this.props.headManager.updateHead(this.props.reduceComponentsToState([...this.props.headManager.mountedInstances],this.props));}};this._hasHeadManager=this.props.headManager&&this.props.headManager.mountedInstances;if(isServer&&this._hasHeadManager){this.props.headManager.mountedInstances.add(this);this.emitChange();}}componentDidMount(){if(this._hasHeadManager){this.props.headManager.mountedInstances.add(this);}this.emitChange();}componentDidUpdate(){this.emitChange();}componentWillUnmount(){if(this._hasHeadManager){this.props.headManager.mountedInstances.delete(this);}this.emitChange();}render(){return null;}}exports.default=_default; + +/Users/jarredsumner/Code/esdev/src/api/demo/./node_modules/next/./dist/client/../next-server/lib/./side-effect.js:1:191 190 diff --git a/outdir/index.css b/outdir/index.css new file mode 100644 index 000000000..7c27b2d24 --- /dev/null +++ b/outdir/index.css @@ -0,0 +1,113 @@ +/* src/api/demo/styles/Home.module.css */ +.container { + min-height: 100vh; + padding: 0 0.5rem; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 100vh; +} +.main { + padding: 5rem 0; + flex: 1; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} +.footer { + width: 100%; + height: 100px; + border-top: 1px solid #eaeaea; + display: flex; + justify-content: center; + align-items: center; +} +.footer a { + display: flex; + justify-content: center; + align-items: center; + flex-grow: 1; +} +.title a { + color: #0070f3; + text-decoration: none; +} +.title a:hover, +.title a:focus, +.title a:active { + text-decoration: underline; +} +.title { + margin: 0; + line-height: 1.15; + font-size: 4rem; +} +.title, +.description { + text-align: center; +} +.description { + line-height: 1.5; + font-size: 1.5rem; +} +.code { + background: #fafafa; + border-radius: 5px; + padding: 0.75rem; + font-size: 1.1rem; + font-family: + Menlo, + Monaco, + Lucida Console, + Liberation Mono, + DejaVu Sans Mono, + Bitstream Vera Sans Mono, + Courier New, + monospace; +} +.grid { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + max-width: 800px; + margin-top: 3rem; +} +.card { + margin: 1rem; + padding: 1.5rem; + text-align: left; + color: inherit; + text-decoration: none; + border: 1px solid #eaeaea; + border-radius: 10px; + transition: color 0.15s ease, border-color 0.15s ease; + width: 45%; +} +.card:hover, +.card:focus, +.card:active { + color: #0070f3; + border-color: #0070f3; +} +.card h2 { + margin: 0 0 1rem 0; + font-size: 1.5rem; +} +.card p { + margin: 0; + font-size: 1.25rem; + line-height: 1.5; +} +.logo { + height: 1em; + margin-left: 0.5rem; +} +@media (max-width: 600px) { + .grid { + width: 100%; + flex-direction: column; + } +} diff --git a/outdir/index.js b/outdir/index.js new file mode 100644 index 000000000..43bfebf71 --- /dev/null +++ b/outdir/index.js @@ -0,0 +1,2338 @@ +(() => { + var __create = Object.create; + var __defProp = Object.defineProperty; + var __getProtoOf = Object.getPrototypeOf; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __markAsModule = (target) => __defProp(target, "__esModule", {value: true}); + var __commonJS = (cb, mod) => () => (mod || cb((mod = {exports: {}}).exports, mod), mod.exports); + var __reExport = (target, module, desc) => { + if (module && typeof module === "object" || typeof module === "function") { + for (let key of __getOwnPropNames(module)) + if (!__hasOwnProp.call(target, key) && key !== "default") + __defProp(target, key, {get: () => module[key], enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable}); + } + return target; + }; + var __toModule = (module) => { + return __reExport(__markAsModule(__defProp(module != null ? __create(__getProtoOf(module)) : {}, "default", module && module.__esModule && "default" in module ? {get: () => module.default, enumerable: true} : {value: module, enumerable: true})), module); + }; + + // src/api/demo/node_modules/.pnpm/object-assign@4.1.1/node_modules/object-assign/index.js + var require_object_assign = __commonJS((exports, module) => { + "use strict"; + var getOwnPropertySymbols = Object.getOwnPropertySymbols; + var hasOwnProperty = Object.prototype.hasOwnProperty; + var propIsEnumerable = Object.prototype.propertyIsEnumerable; + function toObject(val) { + if (val === null || val === void 0) { + throw new TypeError("Object.assign cannot be called with null or undefined"); + } + return Object(val); + } + function shouldUseNative() { + try { + if (!Object.assign) { + return false; + } + var test1 = new String("abc"); + test1[5] = "de"; + if (Object.getOwnPropertyNames(test1)[0] === "5") { + return false; + } + var test2 = {}; + for (var i = 0; i < 10; i++) { + test2["_" + String.fromCharCode(i)] = i; + } + var order2 = Object.getOwnPropertyNames(test2).map(function(n) { + return test2[n]; + }); + if (order2.join("") !== "0123456789") { + return false; + } + var test3 = {}; + "abcdefghijklmnopqrst".split("").forEach(function(letter) { + test3[letter] = letter; + }); + if (Object.keys(Object.assign({}, test3)).join("") !== "abcdefghijklmnopqrst") { + return false; + } + return true; + } catch (err) { + return false; + } + } + module.exports = shouldUseNative() ? Object.assign : function(target, source) { + var from; + var to = toObject(target); + var symbols; + for (var s = 1; s < arguments.length; s++) { + from = Object(arguments[s]); + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } + if (getOwnPropertySymbols) { + symbols = getOwnPropertySymbols(from); + for (var i = 0; i < symbols.length; i++) { + if (propIsEnumerable.call(from, symbols[i])) { + to[symbols[i]] = from[symbols[i]]; + } + } + } + } + return to; + }; + }); + + // src/api/demo/node_modules/.pnpm/react@17.0.2/node_modules/react/cjs/react.development.js + var require_react_development = __commonJS((exports) => { + "use strict"; + if (true) { + (function() { + "use strict"; + var _assign = require_object_assign(); + var ReactVersion = "17.0.2"; + var REACT_ELEMENT_TYPE = 60103; + var REACT_PORTAL_TYPE = 60106; + exports.Fragment = 60107; + exports.StrictMode = 60108; + exports.Profiler = 60114; + var REACT_PROVIDER_TYPE = 60109; + var REACT_CONTEXT_TYPE = 60110; + var REACT_FORWARD_REF_TYPE = 60112; + exports.Suspense = 60113; + var REACT_SUSPENSE_LIST_TYPE = 60120; + var REACT_MEMO_TYPE = 60115; + var REACT_LAZY_TYPE = 60116; + var REACT_BLOCK_TYPE = 60121; + var REACT_SERVER_BLOCK_TYPE = 60122; + var REACT_FUNDAMENTAL_TYPE = 60117; + var REACT_SCOPE_TYPE = 60119; + var REACT_OPAQUE_ID_TYPE = 60128; + var REACT_DEBUG_TRACING_MODE_TYPE = 60129; + var REACT_OFFSCREEN_TYPE = 60130; + var REACT_LEGACY_HIDDEN_TYPE = 60131; + if (typeof Symbol === "function" && Symbol.for) { + var symbolFor = Symbol.for; + REACT_ELEMENT_TYPE = symbolFor("react.element"); + REACT_PORTAL_TYPE = symbolFor("react.portal"); + exports.Fragment = symbolFor("react.fragment"); + exports.StrictMode = symbolFor("react.strict_mode"); + exports.Profiler = symbolFor("react.profiler"); + REACT_PROVIDER_TYPE = symbolFor("react.provider"); + REACT_CONTEXT_TYPE = symbolFor("react.context"); + REACT_FORWARD_REF_TYPE = symbolFor("react.forward_ref"); + exports.Suspense = symbolFor("react.suspense"); + REACT_SUSPENSE_LIST_TYPE = symbolFor("react.suspense_list"); + REACT_MEMO_TYPE = symbolFor("react.memo"); + REACT_LAZY_TYPE = symbolFor("react.lazy"); + REACT_BLOCK_TYPE = symbolFor("react.block"); + REACT_SERVER_BLOCK_TYPE = symbolFor("react.server.block"); + REACT_FUNDAMENTAL_TYPE = symbolFor("react.fundamental"); + REACT_SCOPE_TYPE = symbolFor("react.scope"); + REACT_OPAQUE_ID_TYPE = symbolFor("react.opaque.id"); + REACT_DEBUG_TRACING_MODE_TYPE = symbolFor("react.debug_trace_mode"); + REACT_OFFSCREEN_TYPE = symbolFor("react.offscreen"); + REACT_LEGACY_HIDDEN_TYPE = symbolFor("react.legacy_hidden"); + } + var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; + var FAUX_ITERATOR_SYMBOL = "@@iterator"; + function getIteratorFn(maybeIterable) { + if (maybeIterable === null || typeof maybeIterable !== "object") { + return null; + } + var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; + if (typeof maybeIterator === "function") { + return maybeIterator; + } + return null; + } + var ReactCurrentDispatcher = { + current: null + }; + var ReactCurrentBatchConfig = { + transition: 0 + }; + var ReactCurrentOwner = { + current: null + }; + var ReactDebugCurrentFrame = {}; + var currentExtraStackFrame = null; + function setExtraStackFrame(stack) { + { + currentExtraStackFrame = stack; + } + } + { + ReactDebugCurrentFrame.setExtraStackFrame = function(stack) { + { + currentExtraStackFrame = stack; + } + }; + ReactDebugCurrentFrame.getCurrentStack = null; + ReactDebugCurrentFrame.getStackAddendum = function() { + var stack = ""; + if (currentExtraStackFrame) { + stack += currentExtraStackFrame; + } + var impl = ReactDebugCurrentFrame.getCurrentStack; + if (impl) { + stack += impl() || ""; + } + return stack; + }; + } + var IsSomeRendererActing = { + current: false + }; + var ReactSharedInternals = { + ReactCurrentDispatcher, + ReactCurrentBatchConfig, + ReactCurrentOwner, + IsSomeRendererActing, + assign: _assign + }; + { + ReactSharedInternals.ReactDebugCurrentFrame = ReactDebugCurrentFrame; + } + function warn(format) { + { + for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + printWarning("warn", format, args); + } + } + function error(format) { + { + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; + } + printWarning("error", format, args); + } + } + function printWarning(level, format, args) { + { + var ReactDebugCurrentFrame2 = ReactSharedInternals.ReactDebugCurrentFrame; + var stack = ReactDebugCurrentFrame2.getStackAddendum(); + if (stack !== "") { + format += "%s"; + args = args.concat([stack]); + } + var argsWithFormat = args.map(function(item) { + return "" + item; + }); + argsWithFormat.unshift("Warning: " + format); + Function.prototype.apply.call(console[level], console, argsWithFormat); + } + } + var didWarnStateUpdateForUnmountedComponent = {}; + function warnNoop(publicInstance, callerName) { + { + var _constructor = publicInstance.constructor; + var componentName = _constructor && (_constructor.displayName || _constructor.name) || "ReactClass"; + var warningKey = componentName + "." + callerName; + if (didWarnStateUpdateForUnmountedComponent[warningKey]) { + return; + } + error("Can't call %s on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to `this.state` directly or define a `state = {};` class property with the desired state in the %s component.", callerName, componentName); + didWarnStateUpdateForUnmountedComponent[warningKey] = true; + } + } + var ReactNoopUpdateQueue = { + isMounted: function(publicInstance) { + return false; + }, + enqueueForceUpdate: function(publicInstance, callback, callerName) { + warnNoop(publicInstance, "forceUpdate"); + }, + enqueueReplaceState: function(publicInstance, completeState, callback, callerName) { + warnNoop(publicInstance, "replaceState"); + }, + enqueueSetState: function(publicInstance, partialState, callback, callerName) { + warnNoop(publicInstance, "setState"); + } + }; + var emptyObject = {}; + { + Object.freeze(emptyObject); + } + function Component(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + Component.prototype.isReactComponent = {}; + Component.prototype.setState = function(partialState, callback) { + if (!(typeof partialState === "object" || typeof partialState === "function" || partialState == null)) { + { + throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables."); + } + } + this.updater.enqueueSetState(this, partialState, callback, "setState"); + }; + Component.prototype.forceUpdate = function(callback) { + this.updater.enqueueForceUpdate(this, callback, "forceUpdate"); + }; + { + var deprecatedAPIs = { + isMounted: ["isMounted", "Instead, make sure to clean up subscriptions and pending requests in componentWillUnmount to prevent memory leaks."], + replaceState: ["replaceState", "Refactor your code to use setState instead (see https://github.com/facebook/react/issues/3236)."] + }; + var defineDeprecationWarning = function(methodName, info) { + Object.defineProperty(Component.prototype, methodName, { + get: function() { + warn("%s(...) is deprecated in plain JavaScript React classes. %s", info[0], info[1]); + return void 0; + } + }); + }; + for (var fnName in deprecatedAPIs) { + if (deprecatedAPIs.hasOwnProperty(fnName)) { + defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); + } + } + } + function ComponentDummy() { + } + ComponentDummy.prototype = Component.prototype; + function PureComponent(props, context, updater) { + this.props = props; + this.context = context; + this.refs = emptyObject; + this.updater = updater || ReactNoopUpdateQueue; + } + var pureComponentPrototype = PureComponent.prototype = new ComponentDummy(); + pureComponentPrototype.constructor = PureComponent; + _assign(pureComponentPrototype, Component.prototype); + pureComponentPrototype.isPureReactComponent = true; + function createRef() { + var refObject = { + current: null + }; + { + Object.seal(refObject); + } + return refObject; + } + function getWrappedName(outerType, innerType, wrapperName) { + var functionName = innerType.displayName || innerType.name || ""; + return outerType.displayName || (functionName !== "" ? wrapperName + "(" + functionName + ")" : wrapperName); + } + function getContextName(type) { + return type.displayName || "Context"; + } + function getComponentName(type) { + if (type == null) { + return null; + } + { + if (typeof type.tag === "number") { + error("Received an unexpected object in getComponentName(). This is likely a bug in React. Please file an issue."); + } + } + if (typeof type === "function") { + return type.displayName || type.name || null; + } + if (typeof type === "string") { + return type; + } + switch (type) { + case exports.Fragment: + return "Fragment"; + case REACT_PORTAL_TYPE: + return "Portal"; + case exports.Profiler: + return "Profiler"; + case exports.StrictMode: + return "StrictMode"; + case exports.Suspense: + return "Suspense"; + case REACT_SUSPENSE_LIST_TYPE: + return "SuspenseList"; + } + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_CONTEXT_TYPE: + var context = type; + return getContextName(context) + ".Consumer"; + case REACT_PROVIDER_TYPE: + var provider = type; + return getContextName(provider._context) + ".Provider"; + case REACT_FORWARD_REF_TYPE: + return getWrappedName(type, type.render, "ForwardRef"); + case REACT_MEMO_TYPE: + return getComponentName(type.type); + case REACT_BLOCK_TYPE: + return getComponentName(type._render); + case REACT_LAZY_TYPE: { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + try { + return getComponentName(init(payload)); + } catch (x) { + return null; + } + } + } + } + return null; + } + var hasOwnProperty = Object.prototype.hasOwnProperty; + var RESERVED_PROPS = { + key: true, + ref: true, + __self: true, + __source: true + }; + var specialPropKeyWarningShown, specialPropRefWarningShown, didWarnAboutStringRefs; + { + didWarnAboutStringRefs = {}; + } + function hasValidRef(config) { + { + if (hasOwnProperty.call(config, "ref")) { + var getter = Object.getOwnPropertyDescriptor(config, "ref").get; + if (getter && getter.isReactWarning) { + return false; + } + } + } + return config.ref !== void 0; + } + function hasValidKey(config) { + { + if (hasOwnProperty.call(config, "key")) { + var getter = Object.getOwnPropertyDescriptor(config, "key").get; + if (getter && getter.isReactWarning) { + return false; + } + } + } + return config.key !== void 0; + } + function defineKeyPropWarningGetter(props, displayName) { + var warnAboutAccessingKey = function() { + { + if (!specialPropKeyWarningShown) { + specialPropKeyWarningShown = true; + error("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", displayName); + } + } + }; + warnAboutAccessingKey.isReactWarning = true; + Object.defineProperty(props, "key", { + get: warnAboutAccessingKey, + configurable: true + }); + } + function defineRefPropWarningGetter(props, displayName) { + var warnAboutAccessingRef = function() { + { + if (!specialPropRefWarningShown) { + specialPropRefWarningShown = true; + error("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)", displayName); + } + } + }; + warnAboutAccessingRef.isReactWarning = true; + Object.defineProperty(props, "ref", { + get: warnAboutAccessingRef, + configurable: true + }); + } + function warnIfStringRefCannotBeAutoConverted(config) { + { + if (typeof config.ref === "string" && ReactCurrentOwner.current && config.__self && ReactCurrentOwner.current.stateNode !== config.__self) { + var componentName = getComponentName(ReactCurrentOwner.current.type); + if (!didWarnAboutStringRefs[componentName]) { + error('Component "%s" contains the string ref "%s". Support for string refs will be removed in a future major release. This case cannot be automatically converted to an arrow function. We ask you to manually fix this case by using useRef() or createRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref', componentName, config.ref); + didWarnAboutStringRefs[componentName] = true; + } + } + } + } + var ReactElement = function(type, key, ref, self2, source, owner, props) { + var element = { + $$typeof: REACT_ELEMENT_TYPE, + type, + key, + ref, + props, + _owner: owner + }; + { + element._store = {}; + Object.defineProperty(element._store, "validated", { + configurable: false, + enumerable: false, + writable: true, + value: false + }); + Object.defineProperty(element, "_self", { + configurable: false, + enumerable: false, + writable: false, + value: self2 + }); + Object.defineProperty(element, "_source", { + configurable: false, + enumerable: false, + writable: false, + value: source + }); + if (Object.freeze) { + Object.freeze(element.props); + Object.freeze(element); + } + } + return element; + }; + function createElement(type, config, children) { + var propName; + var props = {}; + var key = null; + var ref = null; + var self2 = null; + var source = null; + if (config != null) { + if (hasValidRef(config)) { + ref = config.ref; + { + warnIfStringRefCannotBeAutoConverted(config); + } + } + if (hasValidKey(config)) { + key = "" + config.key; + } + self2 = config.__self === void 0 ? null : config.__self; + source = config.__source === void 0 ? null : config.__source; + for (propName in config) { + if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { + props[propName] = config[propName]; + } + } + } + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + { + if (Object.freeze) { + Object.freeze(childArray); + } + } + props.children = childArray; + } + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; + for (propName in defaultProps) { + if (props[propName] === void 0) { + props[propName] = defaultProps[propName]; + } + } + } + { + if (key || ref) { + var displayName = typeof type === "function" ? type.displayName || type.name || "Unknown" : type; + if (key) { + defineKeyPropWarningGetter(props, displayName); + } + if (ref) { + defineRefPropWarningGetter(props, displayName); + } + } + } + return ReactElement(type, key, ref, self2, source, ReactCurrentOwner.current, props); + } + function cloneAndReplaceKey(oldElement, newKey) { + var newElement = ReactElement(oldElement.type, newKey, oldElement.ref, oldElement._self, oldElement._source, oldElement._owner, oldElement.props); + return newElement; + } + function cloneElement(element, config, children) { + if (!!(element === null || element === void 0)) { + { + throw Error("React.cloneElement(...): The argument must be a React element, but you passed " + element + "."); + } + } + var propName; + var props = _assign({}, element.props); + var key = element.key; + var ref = element.ref; + var self2 = element._self; + var source = element._source; + var owner = element._owner; + if (config != null) { + if (hasValidRef(config)) { + ref = config.ref; + owner = ReactCurrentOwner.current; + } + if (hasValidKey(config)) { + key = "" + config.key; + } + var defaultProps; + if (element.type && element.type.defaultProps) { + defaultProps = element.type.defaultProps; + } + for (propName in config) { + if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) { + if (config[propName] === void 0 && defaultProps !== void 0) { + props[propName] = defaultProps[propName]; + } else { + props[propName] = config[propName]; + } + } + } + } + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + props.children = childArray; + } + return ReactElement(element.type, key, ref, self2, source, owner, props); + } + function isValidElement(object) { + return typeof object === "object" && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; + } + var SEPARATOR = "."; + var SUBSEPARATOR = ":"; + function escape(key) { + var escapeRegex = /[=:]/g; + var escaperLookup = { + "=": "=0", + ":": "=2" + }; + var escapedString = key.replace(escapeRegex, function(match) { + return escaperLookup[match]; + }); + return "$" + escapedString; + } + var didWarnAboutMaps = false; + var userProvidedKeyEscapeRegex = /\/+/g; + function escapeUserProvidedKey(text) { + return text.replace(userProvidedKeyEscapeRegex, "$&/"); + } + function getElementKey(element, index) { + if (typeof element === "object" && element !== null && element.key != null) { + return escape("" + element.key); + } + return index.toString(36); + } + function mapIntoArray(children, array, escapedPrefix, nameSoFar, callback) { + var type = typeof children; + if (type === "undefined" || type === "boolean") { + children = null; + } + var invokeCallback = false; + if (children === null) { + invokeCallback = true; + } else { + switch (type) { + case "string": + case "number": + invokeCallback = true; + break; + case "object": + switch (children.$$typeof) { + case REACT_ELEMENT_TYPE: + case REACT_PORTAL_TYPE: + invokeCallback = true; + } + } + } + if (invokeCallback) { + var _child = children; + var mappedChild = callback(_child); + var childKey = nameSoFar === "" ? SEPARATOR + getElementKey(_child, 0) : nameSoFar; + if (Array.isArray(mappedChild)) { + var escapedChildKey = ""; + if (childKey != null) { + escapedChildKey = escapeUserProvidedKey(childKey) + "/"; + } + mapIntoArray(mappedChild, array, escapedChildKey, "", function(c) { + return c; + }); + } else if (mappedChild != null) { + if (isValidElement(mappedChild)) { + mappedChild = cloneAndReplaceKey(mappedChild, escapedPrefix + (mappedChild.key && (!_child || _child.key !== mappedChild.key) ? escapeUserProvidedKey("" + mappedChild.key) + "/" : "") + childKey); + } + array.push(mappedChild); + } + return 1; + } + var child; + var nextName; + var subtreeCount = 0; + var nextNamePrefix = nameSoFar === "" ? SEPARATOR : nameSoFar + SUBSEPARATOR; + if (Array.isArray(children)) { + for (var i = 0; i < children.length; i++) { + child = children[i]; + nextName = nextNamePrefix + getElementKey(child, i); + subtreeCount += mapIntoArray(child, array, escapedPrefix, nextName, callback); + } + } else { + var iteratorFn = getIteratorFn(children); + if (typeof iteratorFn === "function") { + var iterableChildren = children; + { + if (iteratorFn === iterableChildren.entries) { + if (!didWarnAboutMaps) { + warn("Using Maps as children is not supported. Use an array of keyed ReactElements instead."); + } + didWarnAboutMaps = true; + } + } + var iterator = iteratorFn.call(iterableChildren); + var step; + var ii = 0; + while (!(step = iterator.next()).done) { + child = step.value; + nextName = nextNamePrefix + getElementKey(child, ii++); + subtreeCount += mapIntoArray(child, array, escapedPrefix, nextName, callback); + } + } else if (type === "object") { + var childrenString = "" + children; + { + { + throw Error("Objects are not valid as a React child (found: " + (childrenString === "[object Object]" ? "object with keys {" + Object.keys(children).join(", ") + "}" : childrenString) + "). If you meant to render a collection of children, use an array instead."); + } + } + } + } + return subtreeCount; + } + function mapChildren(children, func, context) { + if (children == null) { + return children; + } + var result = []; + var count = 0; + mapIntoArray(children, result, "", "", function(child) { + return func.call(context, child, count++); + }); + return result; + } + function countChildren(children) { + var n = 0; + mapChildren(children, function() { + n++; + }); + return n; + } + function forEachChildren(children, forEachFunc, forEachContext) { + mapChildren(children, function() { + forEachFunc.apply(this, arguments); + }, forEachContext); + } + function toArray(children) { + return mapChildren(children, function(child) { + return child; + }) || []; + } + function onlyChild(children) { + if (!isValidElement(children)) { + { + throw Error("React.Children.only expected to receive a single React element child."); + } + } + return children; + } + function createContext(defaultValue, calculateChangedBits) { + if (calculateChangedBits === void 0) { + calculateChangedBits = null; + } else { + { + if (calculateChangedBits !== null && typeof calculateChangedBits !== "function") { + error("createContext: Expected the optional second argument to be a function. Instead received: %s", calculateChangedBits); + } + } + } + var context = { + $$typeof: REACT_CONTEXT_TYPE, + _calculateChangedBits: calculateChangedBits, + _currentValue: defaultValue, + _currentValue2: defaultValue, + _threadCount: 0, + Provider: null, + Consumer: null + }; + context.Provider = { + $$typeof: REACT_PROVIDER_TYPE, + _context: context + }; + var hasWarnedAboutUsingNestedContextConsumers = false; + var hasWarnedAboutUsingConsumerProvider = false; + var hasWarnedAboutDisplayNameOnConsumer = false; + { + var Consumer = { + $$typeof: REACT_CONTEXT_TYPE, + _context: context, + _calculateChangedBits: context._calculateChangedBits + }; + Object.defineProperties(Consumer, { + Provider: { + get: function() { + if (!hasWarnedAboutUsingConsumerProvider) { + hasWarnedAboutUsingConsumerProvider = true; + error("Rendering <Context.Consumer.Provider> is not supported and will be removed in a future major release. Did you mean to render <Context.Provider> instead?"); + } + return context.Provider; + }, + set: function(_Provider) { + context.Provider = _Provider; + } + }, + _currentValue: { + get: function() { + return context._currentValue; + }, + set: function(_currentValue) { + context._currentValue = _currentValue; + } + }, + _currentValue2: { + get: function() { + return context._currentValue2; + }, + set: function(_currentValue2) { + context._currentValue2 = _currentValue2; + } + }, + _threadCount: { + get: function() { + return context._threadCount; + }, + set: function(_threadCount) { + context._threadCount = _threadCount; + } + }, + Consumer: { + get: function() { + if (!hasWarnedAboutUsingNestedContextConsumers) { + hasWarnedAboutUsingNestedContextConsumers = true; + error("Rendering <Context.Consumer.Consumer> is not supported and will be removed in a future major release. Did you mean to render <Context.Consumer> instead?"); + } + return context.Consumer; + } + }, + displayName: { + get: function() { + return context.displayName; + }, + set: function(displayName) { + if (!hasWarnedAboutDisplayNameOnConsumer) { + warn("Setting `displayName` on Context.Consumer has no effect. You should set it directly on the context with Context.displayName = '%s'.", displayName); + hasWarnedAboutDisplayNameOnConsumer = true; + } + } + } + }); + context.Consumer = Consumer; + } + { + context._currentRenderer = null; + context._currentRenderer2 = null; + } + return context; + } + var Uninitialized = -1; + var Pending = 0; + var Resolved = 1; + var Rejected = 2; + function lazyInitializer(payload) { + if (payload._status === Uninitialized) { + var ctor = payload._result; + var thenable = ctor(); + var pending = payload; + pending._status = Pending; + pending._result = thenable; + thenable.then(function(moduleObject) { + if (payload._status === Pending) { + var defaultExport = moduleObject.default; + { + if (defaultExport === void 0) { + error("lazy: Expected the result of a dynamic import() call. Instead received: %s\n\nYour code should look like: \n const MyComponent = lazy(() => import('./MyComponent'))", moduleObject); + } + } + var resolved = payload; + resolved._status = Resolved; + resolved._result = defaultExport; + } + }, function(error2) { + if (payload._status === Pending) { + var rejected = payload; + rejected._status = Rejected; + rejected._result = error2; + } + }); + } + if (payload._status === Resolved) { + return payload._result; + } else { + throw payload._result; + } + } + function lazy(ctor) { + var payload = { + _status: -1, + _result: ctor + }; + var lazyType = { + $$typeof: REACT_LAZY_TYPE, + _payload: payload, + _init: lazyInitializer + }; + { + var defaultProps; + var propTypes; + Object.defineProperties(lazyType, { + defaultProps: { + configurable: true, + get: function() { + return defaultProps; + }, + set: function(newDefaultProps) { + error("React.lazy(...): It is not supported to assign `defaultProps` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."); + defaultProps = newDefaultProps; + Object.defineProperty(lazyType, "defaultProps", { + enumerable: true + }); + } + }, + propTypes: { + configurable: true, + get: function() { + return propTypes; + }, + set: function(newPropTypes) { + error("React.lazy(...): It is not supported to assign `propTypes` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."); + propTypes = newPropTypes; + Object.defineProperty(lazyType, "propTypes", { + enumerable: true + }); + } + } + }); + } + return lazyType; + } + function forwardRef(render) { + { + if (render != null && render.$$typeof === REACT_MEMO_TYPE) { + error("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."); + } else if (typeof render !== "function") { + error("forwardRef requires a render function but was given %s.", render === null ? "null" : typeof render); + } else { + if (render.length !== 0 && render.length !== 2) { + error("forwardRef render functions accept exactly two parameters: props and ref. %s", render.length === 1 ? "Did you forget to use the ref parameter?" : "Any additional parameter will be undefined."); + } + } + if (render != null) { + if (render.defaultProps != null || render.propTypes != null) { + error("forwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?"); + } + } + } + var elementType = { + $$typeof: REACT_FORWARD_REF_TYPE, + render + }; + { + var ownName; + Object.defineProperty(elementType, "displayName", { + enumerable: false, + configurable: true, + get: function() { + return ownName; + }, + set: function(name) { + ownName = name; + if (render.displayName == null) { + render.displayName = name; + } + } + }); + } + return elementType; + } + var enableScopeAPI = false; + function isValidElementType(type) { + if (typeof type === "string" || typeof type === "function") { + return true; + } + if (type === exports.Fragment || type === exports.Profiler || type === REACT_DEBUG_TRACING_MODE_TYPE || type === exports.StrictMode || type === exports.Suspense || type === REACT_SUSPENSE_LIST_TYPE || type === REACT_LEGACY_HIDDEN_TYPE || enableScopeAPI) { + return true; + } + if (typeof type === "object" && type !== null) { + if (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_BLOCK_TYPE || type[0] === REACT_SERVER_BLOCK_TYPE) { + return true; + } + } + return false; + } + function memo(type, compare) { + { + if (!isValidElementType(type)) { + error("memo: The first argument must be a component. Instead received: %s", type === null ? "null" : typeof type); + } + } + var elementType = { + $$typeof: REACT_MEMO_TYPE, + type, + compare: compare === void 0 ? null : compare + }; + { + var ownName; + Object.defineProperty(elementType, "displayName", { + enumerable: false, + configurable: true, + get: function() { + return ownName; + }, + set: function(name) { + ownName = name; + if (type.displayName == null) { + type.displayName = name; + } + } + }); + } + return elementType; + } + function resolveDispatcher() { + var dispatcher = ReactCurrentDispatcher.current; + if (!(dispatcher !== null)) { + { + throw Error("Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:\n1. You might have mismatching versions of React and the renderer (such as React DOM)\n2. You might be breaking the Rules of Hooks\n3. You might have more than one copy of React in the same app\nSee https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem."); + } + } + return dispatcher; + } + function useContext(Context, unstable_observedBits) { + var dispatcher = resolveDispatcher(); + { + if (unstable_observedBits !== void 0) { + error("useContext() second argument is reserved for future use in React. Passing it is not supported. You passed: %s.%s", unstable_observedBits, typeof unstable_observedBits === "number" && Array.isArray(arguments[2]) ? "\n\nDid you call array.map(useContext)? Calling Hooks inside a loop is not supported. Learn more at https://reactjs.org/link/rules-of-hooks" : ""); + } + if (Context._context !== void 0) { + var realContext = Context._context; + if (realContext.Consumer === Context) { + error("Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be removed in a future major release. Did you mean to call useContext(Context) instead?"); + } else if (realContext.Provider === Context) { + error("Calling useContext(Context.Provider) is not supported. Did you mean to call useContext(Context) instead?"); + } + } + } + return dispatcher.useContext(Context, unstable_observedBits); + } + function useState(initialState) { + var dispatcher = resolveDispatcher(); + return dispatcher.useState(initialState); + } + function useReducer(reducer, initialArg, init) { + var dispatcher = resolveDispatcher(); + return dispatcher.useReducer(reducer, initialArg, init); + } + function useRef(initialValue) { + var dispatcher = resolveDispatcher(); + return dispatcher.useRef(initialValue); + } + function useEffect(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useEffect(create, deps); + } + function useLayoutEffect(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useLayoutEffect(create, deps); + } + function useCallback(callback, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useCallback(callback, deps); + } + function useMemo(create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useMemo(create, deps); + } + function useImperativeHandle(ref, create, deps) { + var dispatcher = resolveDispatcher(); + return dispatcher.useImperativeHandle(ref, create, deps); + } + function useDebugValue(value, formatterFn) { + { + var dispatcher = resolveDispatcher(); + return dispatcher.useDebugValue(value, formatterFn); + } + } + var disabledDepth = 0; + var prevLog; + var prevInfo; + var prevWarn; + var prevError; + var prevGroup; + var prevGroupCollapsed; + var prevGroupEnd; + function disabledLog() { + } + disabledLog.__reactDisabledLog = true; + function disableLogs() { + { + if (disabledDepth === 0) { + prevLog = console.log; + prevInfo = console.info; + prevWarn = console.warn; + prevError = console.error; + prevGroup = console.group; + prevGroupCollapsed = console.groupCollapsed; + prevGroupEnd = console.groupEnd; + var props = { + configurable: true, + enumerable: true, + value: disabledLog, + writable: true + }; + Object.defineProperties(console, { + info: props, + log: props, + warn: props, + error: props, + group: props, + groupCollapsed: props, + groupEnd: props + }); + } + disabledDepth++; + } + } + function reenableLogs() { + { + disabledDepth--; + if (disabledDepth === 0) { + var props = { + configurable: true, + enumerable: true, + writable: true + }; + Object.defineProperties(console, { + log: _assign({}, props, { + value: prevLog + }), + info: _assign({}, props, { + value: prevInfo + }), + warn: _assign({}, props, { + value: prevWarn + }), + error: _assign({}, props, { + value: prevError + }), + group: _assign({}, props, { + value: prevGroup + }), + groupCollapsed: _assign({}, props, { + value: prevGroupCollapsed + }), + groupEnd: _assign({}, props, { + value: prevGroupEnd + }) + }); + } + if (disabledDepth < 0) { + error("disabledDepth fell below zero. This is a bug in React. Please file an issue."); + } + } + } + var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; + var prefix; + function describeBuiltInComponentFrame(name, source, ownerFn) { + { + if (prefix === void 0) { + try { + throw Error(); + } catch (x) { + var match = x.stack.trim().match(/\n( *(at )?)/); + prefix = match && match[1] || ""; + } + } + return "\n" + prefix + name; + } + } + var reentry = false; + var componentFrameCache; + { + var PossiblyWeakMap = typeof WeakMap === "function" ? WeakMap : Map; + componentFrameCache = new PossiblyWeakMap(); + } + function describeNativeComponentFrame(fn, construct) { + if (!fn || reentry) { + return ""; + } + { + var frame = componentFrameCache.get(fn); + if (frame !== void 0) { + return frame; + } + } + var control; + reentry = true; + var previousPrepareStackTrace = Error.prepareStackTrace; + Error.prepareStackTrace = void 0; + var previousDispatcher; + { + previousDispatcher = ReactCurrentDispatcher$1.current; + ReactCurrentDispatcher$1.current = null; + disableLogs(); + } + try { + if (construct) { + var Fake = function() { + throw Error(); + }; + Object.defineProperty(Fake.prototype, "props", { + set: function() { + throw Error(); + } + }); + if (typeof Reflect === "object" && Reflect.construct) { + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } + fn.call(Fake.prototype); + } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } + fn(); + } + } catch (sample) { + if (sample && control && typeof sample.stack === "string") { + var sampleLines = sample.stack.split("\n"); + var controlLines = control.stack.split("\n"); + var s = sampleLines.length - 1; + var c = controlLines.length - 1; + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + c--; + } + for (; s >= 1 && c >= 0; s--, c--) { + if (sampleLines[s] !== controlLines[c]) { + if (s !== 1 || c !== 1) { + do { + s--; + c--; + if (c < 0 || sampleLines[s] !== controlLines[c]) { + var _frame = "\n" + sampleLines[s].replace(" at new ", " at "); + { + if (typeof fn === "function") { + componentFrameCache.set(fn, _frame); + } + } + return _frame; + } + } while (s >= 1 && c >= 0); + } + break; + } + } + } + } finally { + reentry = false; + { + ReactCurrentDispatcher$1.current = previousDispatcher; + reenableLogs(); + } + Error.prepareStackTrace = previousPrepareStackTrace; + } + var name = fn ? fn.displayName || fn.name : ""; + var syntheticFrame = name ? describeBuiltInComponentFrame(name) : ""; + { + if (typeof fn === "function") { + componentFrameCache.set(fn, syntheticFrame); + } + } + return syntheticFrame; + } + function describeFunctionComponentFrame(fn, source, ownerFn) { + { + return describeNativeComponentFrame(fn, false); + } + } + function shouldConstruct(Component2) { + var prototype = Component2.prototype; + return !!(prototype && prototype.isReactComponent); + } + function describeUnknownElementTypeFrameInDEV(type, source, ownerFn) { + if (type == null) { + return ""; + } + if (typeof type === "function") { + { + return describeNativeComponentFrame(type, shouldConstruct(type)); + } + } + if (typeof type === "string") { + return describeBuiltInComponentFrame(type); + } + switch (type) { + case exports.Suspense: + return describeBuiltInComponentFrame("Suspense"); + case REACT_SUSPENSE_LIST_TYPE: + return describeBuiltInComponentFrame("SuspenseList"); + } + if (typeof type === "object") { + switch (type.$$typeof) { + case REACT_FORWARD_REF_TYPE: + return describeFunctionComponentFrame(type.render); + case REACT_MEMO_TYPE: + return describeUnknownElementTypeFrameInDEV(type.type, source, ownerFn); + case REACT_BLOCK_TYPE: + return describeFunctionComponentFrame(type._render); + case REACT_LAZY_TYPE: { + var lazyComponent = type; + var payload = lazyComponent._payload; + var init = lazyComponent._init; + try { + return describeUnknownElementTypeFrameInDEV(init(payload), source, ownerFn); + } catch (x) { + } + } + } + } + return ""; + } + var loggedTypeFailures = {}; + var ReactDebugCurrentFrame$1 = ReactSharedInternals.ReactDebugCurrentFrame; + function setCurrentlyValidatingElement(element) { + { + if (element) { + var owner = element._owner; + var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null); + ReactDebugCurrentFrame$1.setExtraStackFrame(stack); + } else { + ReactDebugCurrentFrame$1.setExtraStackFrame(null); + } + } + } + function checkPropTypes(typeSpecs, values, location, componentName, element) { + { + var has = Function.call.bind(Object.prototype.hasOwnProperty); + for (var typeSpecName in typeSpecs) { + if (has(typeSpecs, typeSpecName)) { + var error$1 = void 0; + try { + if (typeof typeSpecs[typeSpecName] !== "function") { + var err = Error((componentName || "React class") + ": " + location + " type `" + typeSpecName + "` is invalid; it must be a function, usually from the `prop-types` package, but received `" + typeof typeSpecs[typeSpecName] + "`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`."); + err.name = "Invariant Violation"; + throw err; + } + error$1 = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, "SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"); + } catch (ex) { + error$1 = ex; + } + if (error$1 && !(error$1 instanceof Error)) { + setCurrentlyValidatingElement(element); + error("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).", componentName || "React class", location, typeSpecName, typeof error$1); + setCurrentlyValidatingElement(null); + } + if (error$1 instanceof Error && !(error$1.message in loggedTypeFailures)) { + loggedTypeFailures[error$1.message] = true; + setCurrentlyValidatingElement(element); + error("Failed %s type: %s", location, error$1.message); + setCurrentlyValidatingElement(null); + } + } + } + } + } + function setCurrentlyValidatingElement$1(element) { + { + if (element) { + var owner = element._owner; + var stack = describeUnknownElementTypeFrameInDEV(element.type, element._source, owner ? owner.type : null); + setExtraStackFrame(stack); + } else { + setExtraStackFrame(null); + } + } + } + var propTypesMisspellWarningShown; + { + propTypesMisspellWarningShown = false; + } + function getDeclarationErrorAddendum() { + if (ReactCurrentOwner.current) { + var name = getComponentName(ReactCurrentOwner.current.type); + if (name) { + return "\n\nCheck the render method of `" + name + "`."; + } + } + return ""; + } + function getSourceInfoErrorAddendum(source) { + if (source !== void 0) { + var fileName = source.fileName.replace(/^.*[\\\/]/, ""); + var lineNumber = source.lineNumber; + return "\n\nCheck your code at " + fileName + ":" + lineNumber + "."; + } + return ""; + } + function getSourceInfoErrorAddendumForProps(elementProps) { + if (elementProps !== null && elementProps !== void 0) { + return getSourceInfoErrorAddendum(elementProps.__source); + } + return ""; + } + var ownerHasKeyUseWarning = {}; + function getCurrentComponentErrorInfo(parentType) { + var info = getDeclarationErrorAddendum(); + if (!info) { + var parentName = typeof parentType === "string" ? parentType : parentType.displayName || parentType.name; + if (parentName) { + info = "\n\nCheck the top-level render call using <" + parentName + ">."; + } + } + return info; + } + function validateExplicitKey(element, parentType) { + if (!element._store || element._store.validated || element.key != null) { + return; + } + element._store.validated = true; + var currentComponentErrorInfo = getCurrentComponentErrorInfo(parentType); + if (ownerHasKeyUseWarning[currentComponentErrorInfo]) { + return; + } + ownerHasKeyUseWarning[currentComponentErrorInfo] = true; + var childOwner = ""; + if (element && element._owner && element._owner !== ReactCurrentOwner.current) { + childOwner = " It was passed a child from " + getComponentName(element._owner.type) + "."; + } + { + setCurrentlyValidatingElement$1(element); + error('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.', currentComponentErrorInfo, childOwner); + setCurrentlyValidatingElement$1(null); + } + } + function validateChildKeys(node, parentType) { + if (typeof node !== "object") { + return; + } + if (Array.isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; + if (isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (isValidElement(node)) { + if (node._store) { + node._store.validated = true; + } + } else if (node) { + var iteratorFn = getIteratorFn(node); + if (typeof iteratorFn === "function") { + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); + var step; + while (!(step = iterator.next()).done) { + if (isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); + } + } + } + } + } + } + function validatePropTypes(element) { + { + var type = element.type; + if (type === null || type === void 0 || typeof type === "string") { + return; + } + var propTypes; + if (typeof type === "function") { + propTypes = type.propTypes; + } else if (typeof type === "object" && (type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_MEMO_TYPE)) { + propTypes = type.propTypes; + } else { + return; + } + if (propTypes) { + var name = getComponentName(type); + checkPropTypes(propTypes, element.props, "prop", name, element); + } else if (type.PropTypes !== void 0 && !propTypesMisspellWarningShown) { + propTypesMisspellWarningShown = true; + var _name = getComponentName(type); + error("Component %s declared `PropTypes` instead of `propTypes`. Did you misspell the property assignment?", _name || "Unknown"); + } + if (typeof type.getDefaultProps === "function" && !type.getDefaultProps.isReactClassApproved) { + error("getDefaultProps is only used on classic React.createClass definitions. Use a static property named `defaultProps` instead."); + } + } + } + function validateFragmentProps(fragment) { + { + var keys = Object.keys(fragment.props); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (key !== "children" && key !== "key") { + setCurrentlyValidatingElement$1(fragment); + error("Invalid prop `%s` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.", key); + setCurrentlyValidatingElement$1(null); + break; + } + } + if (fragment.ref !== null) { + setCurrentlyValidatingElement$1(fragment); + error("Invalid attribute `ref` supplied to `React.Fragment`."); + setCurrentlyValidatingElement$1(null); + } + } + } + function createElementWithValidation(type, props, children) { + var validType = isValidElementType(type); + if (!validType) { + var info = ""; + if (type === void 0 || typeof type === "object" && type !== null && Object.keys(type).length === 0) { + info += " You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports."; + } + var sourceInfo = getSourceInfoErrorAddendumForProps(props); + if (sourceInfo) { + info += sourceInfo; + } else { + info += getDeclarationErrorAddendum(); + } + var typeString; + if (type === null) { + typeString = "null"; + } else if (Array.isArray(type)) { + typeString = "array"; + } else if (type !== void 0 && type.$$typeof === REACT_ELEMENT_TYPE) { + typeString = "<" + (getComponentName(type.type) || "Unknown") + " />"; + info = " Did you accidentally export a JSX literal instead of a component?"; + } else { + typeString = typeof type; + } + { + error("React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s", typeString, info); + } + } + var element = createElement.apply(this, arguments); + if (element == null) { + return element; + } + if (validType) { + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], type); + } + } + if (type === exports.Fragment) { + validateFragmentProps(element); + } else { + validatePropTypes(element); + } + return element; + } + var didWarnAboutDeprecatedCreateFactory = false; + function createFactoryWithValidation(type) { + var validatedFactory = createElementWithValidation.bind(null, type); + validatedFactory.type = type; + { + if (!didWarnAboutDeprecatedCreateFactory) { + didWarnAboutDeprecatedCreateFactory = true; + warn("React.createFactory() is deprecated and will be removed in a future major release. Consider using JSX or use React.createElement() directly instead."); + } + Object.defineProperty(validatedFactory, "type", { + enumerable: false, + get: function() { + warn("Factory.type is deprecated. Access the class directly before passing it to createFactory."); + Object.defineProperty(this, "type", { + value: type + }); + return type; + } + }); + } + return validatedFactory; + } + function cloneElementWithValidation(element, props, children) { + var newElement = cloneElement.apply(this, arguments); + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], newElement.type); + } + validatePropTypes(newElement); + return newElement; + } + { + try { + var frozenObject = Object.freeze({}); + new Map([[frozenObject, null]]); + new Set([frozenObject]); + } catch (e) { + } + } + var createElement$1 = createElementWithValidation; + var cloneElement$1 = cloneElementWithValidation; + var createFactory = createFactoryWithValidation; + var Children = { + map: mapChildren, + forEach: forEachChildren, + count: countChildren, + toArray, + only: onlyChild + }; + exports.Children = Children; + exports.Component = Component; + exports.PureComponent = PureComponent; + exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = ReactSharedInternals; + exports.cloneElement = cloneElement$1; + exports.createContext = createContext; + exports.createElement = createElement$1; + exports.createFactory = createFactory; + exports.createRef = createRef; + exports.forwardRef = forwardRef; + exports.isValidElement = isValidElement; + exports.lazy = lazy; + exports.memo = memo; + exports.useCallback = useCallback; + exports.useContext = useContext; + exports.useDebugValue = useDebugValue; + exports.useEffect = useEffect; + exports.useImperativeHandle = useImperativeHandle; + exports.useLayoutEffect = useLayoutEffect; + exports.useMemo = useMemo; + exports.useReducer = useReducer; + exports.useRef = useRef; + exports.useState = useState; + exports.version = ReactVersion; + })(); + } + }); + + // src/api/demo/node_modules/.pnpm/react@17.0.2/node_modules/react/index.js + var require_react = __commonJS((exports, module) => { + "use strict"; + if (false) { + module.exports = null; + } else { + module.exports = require_react_development(); + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/lib/side-effect.js + var require_side_effect = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.default = void 0; + var _react = require_react(); + var isServer = typeof window === "undefined"; + var _default2 = class extends _react.Component { + constructor(props) { + super(props); + this._hasHeadManager = void 0; + this.emitChange = () => { + if (this._hasHeadManager) { + this.props.headManager.updateHead(this.props.reduceComponentsToState([...this.props.headManager.mountedInstances], this.props)); + } + }; + this._hasHeadManager = this.props.headManager && this.props.headManager.mountedInstances; + if (isServer && this._hasHeadManager) { + this.props.headManager.mountedInstances.add(this); + this.emitChange(); + } + } + componentDidMount() { + if (this._hasHeadManager) { + this.props.headManager.mountedInstances.add(this); + } + this.emitChange(); + } + componentDidUpdate() { + this.emitChange(); + } + componentWillUnmount() { + if (this._hasHeadManager) { + this.props.headManager.mountedInstances.delete(this); + } + this.emitChange(); + } + render() { + return null; + } + }; + exports.default = _default2; + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/lib/amp-context.js + var require_amp_context = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.AmpStateContext = void 0; + var _react = _interopRequireDefault(require_react()); + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; + } + var AmpStateContext = /* @__PURE__ */ _react.default.createContext({}); + exports.AmpStateContext = AmpStateContext; + if (true) { + AmpStateContext.displayName = "AmpStateContext"; + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/lib/head-manager-context.js + var require_head_manager_context = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.HeadManagerContext = void 0; + var _react = _interopRequireDefault(require_react()); + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; + } + var HeadManagerContext = /* @__PURE__ */ _react.default.createContext({}); + exports.HeadManagerContext = HeadManagerContext; + if (true) { + HeadManagerContext.displayName = "HeadManagerContext"; + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/lib/amp.js + var require_amp = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.isInAmpMode = isInAmpMode; + exports.useAmp = useAmp; + var _react = _interopRequireDefault(require_react()); + var _ampContext = require_amp_context(); + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; + } + function isInAmpMode({ampFirst = false, hybrid = false, hasQuery = false} = {}) { + return ampFirst || hybrid && hasQuery; + } + function useAmp() { + return isInAmpMode(_react.default.useContext(_ampContext.AmpStateContext)); + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/lib/head.js + var require_head = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.defaultHead = defaultHead; + exports.default = void 0; + var _react = _interopRequireWildcard(require_react()); + var _sideEffect = _interopRequireDefault(require_side_effect()); + var _ampContext = require_amp_context(); + var _headManagerContext = require_head_manager_context(); + var _amp = require_amp(); + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : {default: obj}; + } + function _getRequireWildcardCache() { + if (typeof WeakMap !== "function") + return null; + var cache = new WeakMap(); + _getRequireWildcardCache = function() { + return cache; + }; + return cache; + } + function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } + if (obj === null || typeof obj !== "object" && typeof obj !== "function") { + return {default: obj}; + } + var cache = _getRequireWildcardCache(); + if (cache && cache.has(obj)) { + return cache.get(obj); + } + var newObj = {}; + var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; + if (desc && (desc.get || desc.set)) { + Object.defineProperty(newObj, key, desc); + } else { + newObj[key] = obj[key]; + } + } + } + newObj.default = obj; + if (cache) { + cache.set(obj, newObj); + } + return newObj; + } + function defaultHead(inAmpMode = false) { + const head = [/* @__PURE__ */ _react.default.createElement("meta", {charSet: "utf-8"})]; + if (!inAmpMode) { + head.push(/* @__PURE__ */ _react.default.createElement("meta", {name: "viewport", content: "width=device-width"})); + } + return head; + } + function onlyReactElement(list, child) { + if (typeof child === "string" || typeof child === "number") { + return list; + } + if (child.type === _react.default.Fragment) { + return list.concat(_react.default.Children.toArray(child.props.children).reduce((fragmentList, fragmentChild) => { + if (typeof fragmentChild === "string" || typeof fragmentChild === "number") { + return fragmentList; + } + return fragmentList.concat(fragmentChild); + }, [])); + } + return list.concat(child); + } + var METATYPES = ["name", "httpEquiv", "charSet", "itemProp"]; + function unique() { + const keys = new Set(); + const tags = new Set(); + const metaTypes = new Set(); + const metaCategories = {}; + return (h) => { + let isUnique = true; + let hasKey = false; + if (h.key && typeof h.key !== "number" && h.key.indexOf("$") > 0) { + hasKey = true; + const key = h.key.slice(h.key.indexOf("$") + 1); + if (keys.has(key)) { + isUnique = false; + } else { + keys.add(key); + } + } + switch (h.type) { + case "title": + case "base": + if (tags.has(h.type)) { + isUnique = false; + } else { + tags.add(h.type); + } + break; + case "meta": + for (let i = 0, len = METATYPES.length; i < len; i++) { + const metatype = METATYPES[i]; + if (!h.props.hasOwnProperty(metatype)) + continue; + if (metatype === "charSet") { + if (metaTypes.has(metatype)) { + isUnique = false; + } else { + metaTypes.add(metatype); + } + } else { + const category = h.props[metatype]; + const categories = metaCategories[metatype] || new Set(); + if ((metatype !== "name" || !hasKey) && categories.has(category)) { + isUnique = false; + } else { + categories.add(category); + metaCategories[metatype] = categories; + } + } + } + break; + } + return isUnique; + }; + } + function reduceComponents(headElements, props) { + return headElements.reduce((list, headElement) => { + const headElementChildren = _react.default.Children.toArray(headElement.props.children); + return list.concat(headElementChildren); + }, []).reduce(onlyReactElement, []).reverse().concat(defaultHead(props.inAmpMode)).filter(unique()).reverse().map((c, i) => { + const key = c.key || i; + if (false) { + if (c.type === "link" && c.props["href"] && ["https://fonts.googleapis.com/css"].some((url) => c.props["href"].startsWith(url))) { + const newProps = {...c.props || {}}; + newProps["data-href"] = newProps["href"]; + newProps["href"] = void 0; + return /* @__PURE__ */ _react.default.cloneElement(c, newProps); + } + } + return /* @__PURE__ */ _react.default.cloneElement(c, {key}); + }); + } + function Head2({children}) { + const ampState = (0, _react.useContext)(_ampContext.AmpStateContext); + const headManager = (0, _react.useContext)(_headManagerContext.HeadManagerContext); + return /* @__PURE__ */ _react.default.createElement(_sideEffect.default, {reduceComponentsToState: reduceComponents, headManager, inAmpMode: (0, _amp.isInAmpMode)(ampState)}, children); + } + Head2.rewind = () => { + }; + var _default2 = Head2; + exports.default = _default2; + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/head.js + var require_head2 = __commonJS((exports, module) => { + module.exports = require_head(); + }); + + // src/api/demo/node_modules/.pnpm/@babel+runtime@7.12.5/node_modules/@babel/runtime/helpers/interopRequireDefault.js + var require_interopRequireDefault = __commonJS((exports, module) => { + function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { + default: obj + }; + } + module.exports = _interopRequireDefault; + }); + + // src/api/demo/node_modules/.pnpm/@babel+runtime@7.12.5/node_modules/@babel/runtime/helpers/objectWithoutPropertiesLoose.js + var require_objectWithoutPropertiesLoose = __commonJS((exports, module) => { + function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) + return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) + continue; + target[key] = source[key]; + } + return target; + } + module.exports = _objectWithoutPropertiesLoose; + }); + + // src/api/demo/node_modules/.pnpm/@babel+runtime@7.12.5/node_modules/@babel/runtime/helpers/extends.js + var require_extends = __commonJS((exports, module) => { + function _extends() { + module.exports = _extends = Object.assign || function(target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + return target; + }; + return _extends.apply(this, arguments); + } + module.exports = _extends; + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/lib/to-base-64.js + var require_to_base_64 = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.toBase64 = toBase64; + function toBase64(str) { + if (typeof window === "undefined") { + return Buffer.from(str).toString("base64"); + } else { + return window.btoa(str); + } + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/next-server/server/image-config.js + var require_image_config = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.imageConfigDefault = exports.VALID_LOADERS = void 0; + var VALID_LOADERS = ["default", "imgix", "cloudinary", "akamai"]; + exports.VALID_LOADERS = VALID_LOADERS; + var imageConfigDefault = {deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], path: "/_next/image", loader: "default", domains: []}; + exports.imageConfigDefault = imageConfigDefault; + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/client/request-idle-callback.js + var require_request_idle_callback = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.cancelIdleCallback = exports.requestIdleCallback = void 0; + var requestIdleCallback = typeof self !== "undefined" && self.requestIdleCallback || function(cb) { + let start = Date.now(); + return setTimeout(function() { + cb({didTimeout: false, timeRemaining: function() { + return Math.max(0, 50 - (Date.now() - start)); + }}); + }, 1); + }; + exports.requestIdleCallback = requestIdleCallback; + var cancelIdleCallback = typeof self !== "undefined" && self.cancelIdleCallback || function(id) { + return clearTimeout(id); + }; + exports.cancelIdleCallback = cancelIdleCallback; + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/client/use-intersection.js + var require_use_intersection = __commonJS((exports) => { + "use strict"; + exports.__esModule = true; + exports.useIntersection = useIntersection; + var _react = require_react(); + var _requestIdleCallback = require_request_idle_callback(); + var hasIntersectionObserver = typeof IntersectionObserver !== "undefined"; + function useIntersection({rootMargin, disabled}) { + const isDisabled = disabled || !hasIntersectionObserver; + const unobserve = (0, _react.useRef)(); + const [visible, setVisible] = (0, _react.useState)(false); + const setRef = (0, _react.useCallback)((el) => { + if (unobserve.current) { + unobserve.current(); + unobserve.current = void 0; + } + if (isDisabled || visible) + return; + if (el && el.tagName) { + unobserve.current = observe(el, (isVisible) => isVisible && setVisible(isVisible), {rootMargin}); + } + }, [isDisabled, rootMargin, visible]); + (0, _react.useEffect)(() => { + if (!hasIntersectionObserver) { + if (!visible) { + const idleCallback = (0, _requestIdleCallback.requestIdleCallback)(() => setVisible(true)); + return () => (0, _requestIdleCallback.cancelIdleCallback)(idleCallback); + } + } + }, [visible]); + return [setRef, visible]; + } + function observe(element, callback, options) { + const {id, observer, elements} = createObserver(options); + elements.set(element, callback); + observer.observe(element); + return function unobserve() { + elements.delete(element); + observer.unobserve(element); + if (elements.size === 0) { + observer.disconnect(); + observers.delete(id); + } + }; + } + var observers = new Map(); + function createObserver(options) { + const id = options.rootMargin || ""; + let instance = observers.get(id); + if (instance) { + return instance; + } + const elements = new Map(); + const observer = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + const callback = elements.get(entry.target); + const isVisible = entry.isIntersecting || entry.intersectionRatio > 0; + if (callback && isVisible) { + callback(isVisible); + } + }); + }, options); + observers.set(id, instance = {id, observer, elements}); + return instance; + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/dist/client/image.js + var require_image = __commonJS((exports) => { + "use strict"; + var _interopRequireDefault = require_interopRequireDefault(); + exports.__esModule = true; + exports.default = Image2; + var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require_objectWithoutPropertiesLoose()); + var _extends2 = _interopRequireDefault(require_extends()); + var _react = _interopRequireDefault(require_react()); + var _head = _interopRequireDefault(require_head()); + var _toBase = require_to_base_64(); + var _imageConfig = require_image_config(); + var _useIntersection = require_use_intersection(); + if (typeof window === "undefined") { + ; + global.__NEXT_IMAGE_IMPORTED = true; + } + var VALID_LOADING_VALUES = ["lazy", "eager", void 0]; + var loaders = new Map([["imgix", imgixLoader], ["cloudinary", cloudinaryLoader], ["akamai", akamaiLoader], ["default", defaultLoader]]); + var VALID_LAYOUT_VALUES = ["fill", "fixed", "intrinsic", "responsive", void 0]; + var {deviceSizes: configDeviceSizes, imageSizes: configImageSizes, loader: configLoader, path: configPath, domains: configDomains} = process.env.__NEXT_IMAGE_OPTS || _imageConfig.imageConfigDefault; + var allSizes = [...configDeviceSizes, ...configImageSizes]; + configDeviceSizes.sort((a, b) => a - b); + allSizes.sort((a, b) => a - b); + function getWidths(width, layout, sizes) { + if (sizes && (layout === "fill" || layout === "responsive")) { + const percentSizes = [...sizes.matchAll(/(^|\s)(1?\d?\d)vw/g)].map((m) => parseInt(m[2])); + if (percentSizes.length) { + const smallestRatio = Math.min(...percentSizes) * 0.01; + return {widths: allSizes.filter((s) => s >= configDeviceSizes[0] * smallestRatio), kind: "w"}; + } + return {widths: allSizes, kind: "w"}; + } + if (typeof width !== "number" || layout === "fill" || layout === "responsive") { + return {widths: configDeviceSizes, kind: "w"}; + } + const widths = [...new Set([width, width * 2].map((w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1]))]; + return {widths, kind: "x"}; + } + function generateImgAttrs({src, unoptimized, layout, width, quality, sizes, loader}) { + if (unoptimized) { + return {src, srcSet: void 0, sizes: void 0}; + } + const {widths, kind} = getWidths(width, layout, sizes); + const last = widths.length - 1; + return { + sizes: !sizes && kind === "w" ? "100vw" : sizes, + srcSet: widths.map((w, i) => `${loader({src, quality, width: w})} ${kind === "w" ? w : i + 1}${kind}`).join(", "), + src: loader({src, quality, width: widths[last]}) + }; + } + function getInt(x) { + if (typeof x === "number") { + return x; + } + if (typeof x === "string") { + return parseInt(x, 10); + } + return void 0; + } + function defaultImageLoader(loaderProps) { + const load = loaders.get(configLoader); + if (load) { + return load((0, _extends2.default)({root: configPath}, loaderProps)); + } + throw new Error(`Unknown "loader" found in "next.config.js". Expected: ${_imageConfig.VALID_LOADERS.join(", ")}. Received: ${configLoader}`); + } + function Image2(_ref) { + let {src, sizes, unoptimized = false, priority = false, loading, className, quality, width, height, objectFit, objectPosition, loader = defaultImageLoader} = _ref, all = (0, _objectWithoutPropertiesLoose2.default)(_ref, ["src", "sizes", "unoptimized", "priority", "loading", "className", "quality", "width", "height", "objectFit", "objectPosition", "loader"]); + let rest = all; + let layout = sizes ? "responsive" : "intrinsic"; + let unsized = false; + if ("unsized" in rest) { + unsized = Boolean(rest.unsized); + delete rest["unsized"]; + } else if ("layout" in rest) { + if (rest.layout) + layout = rest.layout; + delete rest["layout"]; + } + if (true) { + if (!src) { + throw new Error(`Image is missing required "src" property. Make sure you pass "src" in props to the \`next/image\` component. Received: ${JSON.stringify({width, height, quality})}`); + } + if (!VALID_LAYOUT_VALUES.includes(layout)) { + throw new Error(`Image with src "${src}" has invalid "layout" property. Provided "${layout}" should be one of ${VALID_LAYOUT_VALUES.map(String).join(",")}.`); + } + if (!VALID_LOADING_VALUES.includes(loading)) { + throw new Error(`Image with src "${src}" has invalid "loading" property. Provided "${loading}" should be one of ${VALID_LOADING_VALUES.map(String).join(",")}.`); + } + if (priority && loading === "lazy") { + throw new Error(`Image with src "${src}" has both "priority" and "loading='lazy'" properties. Only one should be used.`); + } + if (unsized) { + throw new Error(`Image with src "${src}" has deprecated "unsized" property, which was removed in favor of the "layout='fill'" property`); + } + } + let isLazy = !priority && (loading === "lazy" || typeof loading === "undefined"); + if (src && src.startsWith("data:")) { + unoptimized = true; + isLazy = false; + } + const [setRef, isIntersected] = (0, _useIntersection.useIntersection)({rootMargin: "200px", disabled: !isLazy}); + const isVisible = !isLazy || isIntersected; + const widthInt = getInt(width); + const heightInt = getInt(height); + const qualityInt = getInt(quality); + let wrapperStyle; + let sizerStyle; + let sizerSvg; + let imgStyle = {position: "absolute", top: 0, left: 0, bottom: 0, right: 0, boxSizing: "border-box", padding: 0, border: "none", margin: "auto", display: "block", width: 0, height: 0, minWidth: "100%", maxWidth: "100%", minHeight: "100%", maxHeight: "100%", objectFit, objectPosition}; + if (typeof widthInt !== "undefined" && typeof heightInt !== "undefined" && layout !== "fill") { + const quotient = heightInt / widthInt; + const paddingTop = isNaN(quotient) ? "100%" : `${quotient * 100}%`; + if (layout === "responsive") { + wrapperStyle = {display: "block", overflow: "hidden", position: "relative", boxSizing: "border-box", margin: 0}; + sizerStyle = {display: "block", boxSizing: "border-box", paddingTop}; + } else if (layout === "intrinsic") { + wrapperStyle = {display: "inline-block", maxWidth: "100%", overflow: "hidden", position: "relative", boxSizing: "border-box", margin: 0}; + sizerStyle = {boxSizing: "border-box", display: "block", maxWidth: "100%"}; + sizerSvg = `<svg width="${widthInt}" height="${heightInt}" xmlns="http://www.w3.org/2000/svg" version="1.1"/>`; + } else if (layout === "fixed") { + wrapperStyle = {overflow: "hidden", boxSizing: "border-box", display: "inline-block", position: "relative", width: widthInt, height: heightInt}; + } + } else if (typeof widthInt === "undefined" && typeof heightInt === "undefined" && layout === "fill") { + wrapperStyle = {display: "block", overflow: "hidden", position: "absolute", top: 0, left: 0, bottom: 0, right: 0, boxSizing: "border-box", margin: 0}; + } else { + if (true) { + throw new Error(`Image with src "${src}" must use "width" and "height" properties or "layout='fill'" property.`); + } + } + let imgAttributes = {src: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7", srcSet: void 0, sizes: void 0}; + if (isVisible) { + imgAttributes = generateImgAttrs({src, unoptimized, layout, width: widthInt, quality: qualityInt, sizes, loader}); + } + if (unsized) { + wrapperStyle = void 0; + sizerStyle = void 0; + imgStyle = void 0; + } + return /* @__PURE__ */ _react.default.createElement("div", {style: wrapperStyle}, sizerStyle ? /* @__PURE__ */ _react.default.createElement("div", {style: sizerStyle}, sizerSvg ? /* @__PURE__ */ _react.default.createElement("img", {style: {maxWidth: "100%", display: "block", margin: 0, border: "none", padding: 0}, alt: "", "aria-hidden": true, role: "presentation", src: `data:image/svg+xml;base64,${(0, _toBase.toBase64)(sizerSvg)}`}) : null) : null, !isVisible && /* @__PURE__ */ _react.default.createElement("noscript", null, /* @__PURE__ */ _react.default.createElement("img", Object.assign({}, rest, generateImgAttrs({src, unoptimized, layout, width: widthInt, quality: qualityInt, sizes, loader}), {src, decoding: "async", sizes, style: imgStyle, className}))), /* @__PURE__ */ _react.default.createElement("img", Object.assign({}, rest, imgAttributes, {decoding: "async", className, ref: setRef, style: imgStyle})), priority ? /* @__PURE__ */ _react.default.createElement(_head.default, null, /* @__PURE__ */ _react.default.createElement("link", { + key: "__nimg-" + imgAttributes.src + imgAttributes.srcSet + imgAttributes.sizes, + rel: "preload", + as: "image", + href: imgAttributes.srcSet ? void 0 : imgAttributes.src, + imagesrcset: imgAttributes.srcSet, + imagesizes: imgAttributes.sizes + })) : null); + } + function normalizeSrc(src) { + return src[0] === "/" ? src.slice(1) : src; + } + function imgixLoader({root, src, width, quality}) { + const params = ["auto=format", "fit=max", "w=" + width]; + let paramsString = ""; + if (quality) { + params.push("q=" + quality); + } + if (params.length) { + paramsString = "?" + params.join("&"); + } + return `${root}${normalizeSrc(src)}${paramsString}`; + } + function akamaiLoader({root, src, width}) { + return `${root}${normalizeSrc(src)}?imwidth=${width}`; + } + function cloudinaryLoader({root, src, width, quality}) { + const params = ["f_auto", "c_limit", "w_" + width, "q_" + (quality || "auto")]; + let paramsString = params.join(",") + "/"; + return `${root}${paramsString}${normalizeSrc(src)}`; + } + function defaultLoader({root, src, width, quality}) { + if (true) { + const missingValues = []; + if (!src) + missingValues.push("src"); + if (!width) + missingValues.push("width"); + if (missingValues.length > 0) { + throw new Error(`Next Image Optimization requires ${missingValues.join(", ")} to be provided. Make sure you pass them as props to the \`next/image\` component. Received: ${JSON.stringify({src, width, quality})}`); + } + if (src.startsWith("//")) { + throw new Error(`Failed to parse src "${src}" on \`next/image\`, protocol-relative URL (//) must be changed to an absolute URL (http:// or https://)`); + } + if (!src.startsWith("/") && configDomains) { + let parsedSrc; + try { + parsedSrc = new URL(src); + } catch (err) { + console.error(err); + throw new Error(`Failed to parse src "${src}" on \`next/image\`, if using relative image it must start with a leading slash "/" or be an absolute URL (http:// or https://)`); + } + if (!configDomains.includes(parsedSrc.hostname)) { + throw new Error(`Invalid src prop (${src}) on \`next/image\`, hostname "${parsedSrc.hostname}" is not configured under images in your \`next.config.js\` +See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host`); + } + } + } + return `${root}?url=${encodeURIComponent(src)}&w=${width}&q=${quality || 75}`; + } + }); + + // src/api/demo/node_modules/.pnpm/next@10.2.0_react-dom@17.0.2+react@17.0.2/node_modules/next/image.js + var require_image2 = __commonJS((exports, module) => { + module.exports = require_image(); + }); + + // src/api/demo/pages/index.jsx + var import_head = __toModule(require_head2()); + var import_image = __toModule(require_image2()); + + // src/api/demo/styles/Home.module.css + var _default = {}; + + // src/api/demo/pages/index.jsx + function Home() { + return /* @__PURE__ */ React.createElement("div", { + className: _default.container + }, /* @__PURE__ */ React.createElement(import_head.default, null, /* @__PURE__ */ React.createElement("title", null, "Create Next App"), /* @__PURE__ */ React.createElement("meta", { + name: "description", + content: "Generated by create next app" + }), /* @__PURE__ */ React.createElement("link", { + rel: "icon", + href: "/favicon.ico" + })), /* @__PURE__ */ React.createElement("main", { + className: _default.main + }, /* @__PURE__ */ React.createElement("h1", { + className: _default.title + }, "Welcome to ", /* @__PURE__ */ React.createElement("a", { + href: "https://nextjs.org" + }, "Next.js!")), /* @__PURE__ */ React.createElement("p", { + className: _default.description + }, "Get started by editing", " ", /* @__PURE__ */ React.createElement("code", { + className: _default.code + }, "pages/index.js")), /* @__PURE__ */ React.createElement("div", { + className: _default.grid + }, /* @__PURE__ */ React.createElement("a", { + href: "https://nextjs.org/docs", + className: _default.card + }, /* @__PURE__ */ React.createElement("h2", null, "Documentation \u2192"), /* @__PURE__ */ React.createElement("p", null, "Find in-depth information about Next.js features and API.")), /* @__PURE__ */ React.createElement("a", { + href: "https://nextjs.org/learn", + className: _default.card + }, /* @__PURE__ */ React.createElement("h2", null, "Learn \u2192"), /* @__PURE__ */ React.createElement("p", null, "Learn about Next.js in an interactive course with quizzes!")), /* @__PURE__ */ React.createElement("a", { + href: "https://github.com/vercel/next.js/tree/master/examples", + className: _default.card + }, /* @__PURE__ */ React.createElement("h2", null, "Examples \u2192"), /* @__PURE__ */ React.createElement("p", null, "Discover and deploy boilerplate example Next.js projects.")), /* @__PURE__ */ React.createElement("a", { + href: "https://vercel.com/new?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app", + className: _default.card + }, /* @__PURE__ */ React.createElement("h2", null, "Deploy \u2192"), /* @__PURE__ */ React.createElement("p", null, "Instantly deploy your Next.js site to a public URL with Vercel.")))), /* @__PURE__ */ React.createElement("footer", { + className: _default.footer + }, /* @__PURE__ */ React.createElement("a", { + href: "https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app", + target: "_blank", + rel: "noopener noreferrer" + }, "Powered by", " ", /* @__PURE__ */ React.createElement("span", { + className: _default.logo + }, /* @__PURE__ */ React.createElement(import_image.default, { + src: "/vercel.svg", + alt: "Vercel Logo", + width: 72, + height: 16 + }))))); + } +})(); +/* +object-assign +(c) Sindre Sorhus +@license MIT +*/ +/** @license React v17.0.2 + * react.development.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ diff --git a/src/api/demo/pages/index.js b/src/api/demo/pages/index.jsx index 9523fbc8b..9523fbc8b 100644 --- a/src/api/demo/pages/index.js +++ b/src/api/demo/pages/index.jsx diff --git a/src/bundler.zig b/src/bundler.zig index 6ea4d41a8..34983a9b8 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -110,7 +110,7 @@ pub const Bundler = struct { ) !void { var allocator = bundler.allocator; const relative_path = try std.fs.path.relative(bundler.allocator, bundler.fs.top_level_dir, result.source.path.text); - var out_parts = [_]string{ bundler.fs.top_level_dir, relative_path }; + var out_parts = [_]string{ bundler.options.output_dir, relative_path }; const out_path = try std.fs.path.join(bundler.allocator, &out_parts); const ast = result.ast; @@ -302,7 +302,7 @@ pub const Transformer = struct { ); const cwd = opts.absolute_working_dir orelse try std.process.getCwdAlloc(allocator); - const output_dir_parts = [_]string{ cwd, opts.output_dir orelse "out" }; + const output_dir_parts = [_]string{ try std.process.getCwdAlloc(allocator), opts.output_dir orelse "out" }; const output_dir = try std.fs.path.join(allocator, &output_dir_parts); var output_files = try std.ArrayList(options.OutputFile).initCapacity(allocator, opts.entry_points.len); var loader_values = try allocator.alloc(options.Loader, opts.loader_values.len); diff --git a/src/cli.zig b/src/cli.zig index d26e41d65..01240482d 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -310,18 +310,18 @@ pub const Cli = struct { did_write = true; var root_dir = try std.fs.openDirAbsolute(args.absolute_working_dir.?, std.fs.Dir.OpenDirOptions{}); defer root_dir.close(); - // for (result.output_files) |f| { - // try root_dir.makePath(std.fs.path.dirname(f.path) orelse unreachable); + for (result.output_files) |f| { + try root_dir.makePath(std.fs.path.dirname(f.path) orelse unreachable); - // var _handle = try std.fs.createFileAbsolute(f.path, std.fs.File.CreateFlags{ - // .truncate = true, - // }); - // try _handle.seekTo(0); + var _handle = try std.fs.createFileAbsolute(f.path, std.fs.File.CreateFlags{ + .truncate = true, + }); + try _handle.seekTo(0); - // defer _handle.close(); + defer _handle.close(); - // try _handle.writeAll(f.contents); - // } + try _handle.writeAll(f.contents); + } var max_path_len: usize = 0; var max_padded_size: usize = 0; diff --git a/src/fs.zig b/src/fs.zig index ed541d588..86a6550c4 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -10,8 +10,6 @@ const resolvePath = @import("./resolver/resolve_path.zig").resolvePath; // pub const FilesystemImplementation = @import("fs_impl.zig"); -// - threadlocal var scratch_lookup_buffer = [_]u8{0} ** 255; pub const FileSystem = struct { diff --git a/src/hash_map_v2.zig b/src/hash_map_v2.zig new file mode 100644 index 000000000..cad4bd36c --- /dev/null +++ b/src/hash_map_v2.zig @@ -0,0 +1,1818 @@ +// SPDX-License-Identifier: MIT +// Copyright (c) 2015-2021 Zig Contributors +// This file is part of [zig](https://ziglang.org/), which is MIT licensed. +// The MIT license requires this copyright notice to be included in all copies +// and substantial portions of the software. +const std = @import("std"); +const assert = debug.assert; +const autoHash = std.hash.autoHash; +const debug = std.debug; +const warn = debug.warn; +const math = std.math; +const mem = std.mem; +const meta = std.meta; +const trait = meta.trait; +const Allocator = mem.Allocator; +const Wyhash = std.hash.Wyhash; + +/// Finds the max of three numbers +pub fn math_max3(x: anytype, y: anytype, z: anytype) @TypeOf(x, y, z) { + return std.math.max(x, std.math.max(y, z)); +} + +pub fn getAutoHashFn(comptime K: type, comptime Context: type) (fn (Context, K) u64) { + comptime { + assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated + if (K == []const u8) { + @compileError("std.auto_hash.autoHash does not allow slices here (" ++ + @typeName(K) ++ + ") because the intent is unclear. " ++ + "Consider using std.StringHashMap for hashing the contents of []const u8. " ++ + "Alternatively, consider using std.auto_hash.hash or providing your own hash function instead."); + } + } + + return struct { + fn hash(ctx: Context, key: K) u64 { + if (comptime trait.hasUniqueRepresentation(K)) { + return Wyhash.hash(0, std.mem.asBytes(&key)); + } else { + var hasher = Wyhash.init(0); + autoHash(&hasher, key); + return hasher.final(); + } + } + }.hash; +} + +pub fn getAutoEqlFn(comptime K: type, comptime Context: type) (fn (Context, K, K) bool) { + return struct { + fn eql(ctx: Context, a: K, b: K) bool { + return meta.eql(a, b); + } + }.eql; +} + +pub fn AutoHashMap(comptime K: type, comptime V: type) type { + return HashMap(K, V, AutoContext(K), default_max_load_percentage); +} + +pub fn AutoHashMapUnmanaged(comptime K: type, comptime V: type) type { + return HashMapUnmanaged(K, V, AutoContext(K), default_max_load_percentage); +} + +pub fn AutoContext(comptime K: type) type { + return struct { + pub const hash = getAutoHashFn(K, @This()); + pub const eql = getAutoEqlFn(K, @This()); + }; +} + +/// Builtin hashmap for strings as keys. +/// Key memory is managed by the caller. Keys and values +/// will not automatically be freed. +pub fn StringHashMap(comptime V: type) type { + return HashMap([]const u8, V, StringContext, default_max_load_percentage); +} + +/// Key memory is managed by the caller. Keys and values +/// will not automatically be freed. +pub fn StringHashMapUnmanaged(comptime V: type) type { + return HashMapUnmanaged([]const u8, V, StringContext, default_max_load_percentage); +} + +pub const StringContext = struct { + pub fn hash(self: @This(), s: []const u8) u64 { + return hashString(s); + } + pub fn eql(self: @This(), a: []const u8, b: []const u8) bool { + return eqlString(a, b); + } +}; + +pub fn eqlString(a: []const u8, b: []const u8) bool { + return mem.eql(u8, a, b); +} + +pub fn hashString(s: []const u8) u64 { + return std.hash.Wyhash.hash(0, s); +} + +/// Deprecated use `default_max_load_percentage` +pub const DefaultMaxLoadPercentage = default_max_load_percentage; + +pub const default_max_load_percentage = 80; + +/// This function issues a compile error with a helpful message if there +/// is a problem with the provided context type. A context must have the following +/// member functions: +/// - hash(self, PseudoKey) Hash +/// - eql(self, PseudoKey, Key) bool +/// If you are passing a context to a *Adapted function, PseudoKey is the type +/// of the key parameter. Otherwise, when creating a HashMap or HashMapUnmanaged +/// type, PseudoKey = Key = K. +pub fn verifyContext(comptime RawContext: type, comptime PseudoKey: type, comptime Key: type, comptime Hash: type) void { + comptime { + var allow_const_ptr = false; + var allow_mutable_ptr = false; + // Context is the actual namespace type. RawContext may be a pointer to Context. + var Context = RawContext; + // Make sure the context is a namespace type which may have member functions + switch (@typeInfo(Context)) { + .Struct, .Union => {}, + // Special-case .Opaque for a better error message + .Opaque => @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context) ++ " because it is opaque. Use a pointer instead."), + .Pointer => |ptr| { + if (ptr.size != .One) { + @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context) ++ " because it is not a single pointer."); + } + Context = ptr.child; + allow_const_ptr = true; + allow_mutable_ptr = !ptr.is_const; + switch (@typeInfo(Context)) { + .Struct, .Union, .Opaque => {}, + else => @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context)), + } + }, + else => @compileError("Hash context must be a type with hash and eql member functions. Cannot use " ++ @typeName(Context)), + } + + // Keep track of multiple errors so we can report them all. + var errors: []const u8 = ""; + + // Put common errors here, they will only be evaluated + // if the error is actually triggered. + const lazy = struct { + const prefix = "\n "; + const deep_prefix = prefix ++ " "; + const hash_signature = "fn (self, " ++ @typeName(PseudoKey) ++ ") " ++ @typeName(Hash); + const eql_signature = "fn (self, " ++ @typeName(PseudoKey) ++ ", " ++ @typeName(Key) ++ ") bool"; + const err_invalid_hash_signature = prefix ++ @typeName(Context) ++ ".hash must be " ++ hash_signature ++ + deep_prefix ++ "but is actually " ++ @typeName(@TypeOf(Context.hash)); + const err_invalid_eql_signature = prefix ++ @typeName(Context) ++ ".eql must be " ++ eql_signature ++ + deep_prefix ++ "but is actually " ++ @typeName(@TypeOf(Context.eql)); + }; + + // Verify Context.hash(self, PseudoKey) => Hash + if (@hasDecl(Context, "hash")) { + const hash = Context.hash; + const info = @typeInfo(@TypeOf(hash)); + if (info == .Fn) { + const func = info.Fn; + if (func.args.len != 2) { + errors = errors ++ lazy.err_invalid_hash_signature; + } else { + var emitted_signature = false; + if (func.args[0].arg_type) |Self| { + if (Self == Context) { + // pass, this is always fine. + } else if (Self == *const Context) { + if (!allow_const_ptr) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_hash_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self); + errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value."; + } + } else if (Self == *Context) { + if (!allow_mutable_ptr) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_hash_signature; + emitted_signature = true; + } + if (!allow_const_ptr) { + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self); + errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value."; + } else { + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ " or " ++ @typeName(*const Context) ++ ", but is " ++ @typeName(Self); + errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be non-const because it is passed by const pointer."; + } + } + } else { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_hash_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context); + if (allow_const_ptr) { + errors = errors ++ " or " ++ @typeName(*const Context); + if (allow_mutable_ptr) { + errors = errors ++ " or " ++ @typeName(*Context); + } + } + errors = errors ++ ", but is " ++ @typeName(Self); + } + } + if (func.args[1].arg_type != null and func.args[1].arg_type.? != PseudoKey) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_hash_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "Second parameter must be " ++ @typeName(PseudoKey) ++ ", but is " ++ @typeName(func.args[1].arg_type.?); + } + if (func.return_type != null and func.return_type.? != Hash) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_hash_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "Return type must be " ++ @typeName(Hash) ++ ", but was " ++ @typeName(func.return_type.?); + } + // If any of these are generic (null), we cannot verify them. + // The call sites check the return type, but cannot check the + // parameters. This may cause compile errors with generic hash/eql functions. + } + } else { + errors = errors ++ lazy.err_invalid_hash_signature; + } + } else { + errors = errors ++ lazy.prefix ++ @typeName(Context) ++ " must declare a hash function with signature " ++ lazy.hash_signature; + } + + // Verify Context.eql(self, PseudoKey, Key) => bool + if (@hasDecl(Context, "eql")) { + const eql = Context.eql; + const info = @typeInfo(@TypeOf(eql)); + if (info == .Fn) { + const func = info.Fn; + if (func.args.len != 3) { + errors = errors ++ lazy.err_invalid_eql_signature; + } else { + var emitted_signature = false; + if (func.args[0].arg_type) |Self| { + if (Self == Context) { + // pass, this is always fine. + } else if (Self == *const Context) { + if (!allow_const_ptr) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_eql_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self); + errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value."; + } + } else if (Self == *Context) { + if (!allow_mutable_ptr) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_eql_signature; + emitted_signature = true; + } + if (!allow_const_ptr) { + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ ", but is " ++ @typeName(Self); + errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be a pointer because it is passed by value."; + } else { + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context) ++ " or " ++ @typeName(*const Context) ++ ", but is " ++ @typeName(Self); + errors = errors ++ lazy.deep_prefix ++ "Note: Cannot be non-const because it is passed by const pointer."; + } + } + } else { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_eql_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "First parameter must be " ++ @typeName(Context); + if (allow_const_ptr) { + errors = errors ++ " or " ++ @typeName(*const Context); + if (allow_mutable_ptr) { + errors = errors ++ " or " ++ @typeName(*Context); + } + } + errors = errors ++ ", but is " ++ @typeName(Self); + } + } + if (func.args[1].arg_type.? != PseudoKey) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_eql_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "Second parameter must be " ++ @typeName(PseudoKey) ++ ", but is " ++ @typeName(func.args[1].arg_type.?); + } + if (func.args[2].arg_type.? != Key) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_eql_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "Third parameter must be " ++ @typeName(Key) ++ ", but is " ++ @typeName(func.args[2].arg_type.?); + } + if (func.return_type.? != bool) { + if (!emitted_signature) { + errors = errors ++ lazy.err_invalid_eql_signature; + emitted_signature = true; + } + errors = errors ++ lazy.deep_prefix ++ "Return type must be bool, but was " ++ @typeName(func.return_type.?); + } + // If any of these are generic (null), we cannot verify them. + // The call sites check the return type, but cannot check the + // parameters. This may cause compile errors with generic hash/eql functions. + } + } else { + errors = errors ++ lazy.err_invalid_eql_signature; + } + } else { + errors = errors ++ lazy.prefix ++ @typeName(Context) ++ " must declare a eql function with signature " ++ lazy.eql_signature; + } + + if (errors.len != 0) { + // errors begins with a newline (from lazy.prefix) + @compileError("Problems found with hash context type " ++ @typeName(Context) ++ ":" ++ errors); + } + } +} + +/// General purpose hash table. +/// No order is guaranteed and any modification invalidates live iterators. +/// It provides fast operations (lookup, insertion, deletion) with quite high +/// load factors (up to 80% by default) for a low memory usage. +/// For a hash map that can be initialized directly that does not store an Allocator +/// field, see `HashMapUnmanaged`. +/// If iterating over the table entries is a strong usecase and needs to be fast, +/// prefer the alternative `std.ArrayHashMap`. +/// Context must be a struct type with two member functions: +/// hash(self, K) u64 +/// eql(self, K, K) bool +/// Adapted variants of many functions are provided. These variants +/// take a pseudo key instead of a key. Their context must have the functions: +/// hash(self, PseudoKey) u64 +/// eql(self, PseudoKey, K) bool +pub fn HashMap( + comptime K: type, + comptime V: type, + comptime Context: type, + comptime max_load_percentage: u64, +) type { + comptime verifyContext(Context, K, K, u64); + return struct { + unmanaged: Unmanaged, + allocator: *Allocator, + ctx: Context, + + /// The type of the unmanaged hash map underlying this wrapper + pub const Unmanaged = HashMapUnmanaged(K, V, Context, max_load_percentage); + /// An entry, containing pointers to a key and value stored in the map + pub const Entry = Unmanaged.Entry; + /// A copy of a key and value which are no longer in the map + pub const KV = Unmanaged.KV; + /// The integer type that is the result of hashing + pub const Hash = Unmanaged.Hash; + /// The iterator type returned by iterator() + pub const Iterator = Unmanaged.Iterator; + /// The integer type used to store the size of the map + pub const Size = Unmanaged.Size; + /// The type returned from getOrPut and variants + pub const GetOrPutResult = Unmanaged.GetOrPutResult; + + const Self = @This(); + + /// Create a managed hash map with an empty context. + /// If the context is not zero-sized, you must use + /// initContext(allocator, ctx) instead. + pub fn init(allocator: *Allocator) Self { + if (@sizeOf(Context) != 0) { + @compileError("Context must be specified! Call initContext(allocator, ctx) instead."); + } + return .{ + .unmanaged = .{}, + .allocator = allocator, + .ctx = undefined, // ctx is zero-sized so this is safe. + }; + } + + /// Create a managed hash map with a context + pub fn initContext(allocator: *Allocator, ctx: Context) Self { + return .{ + .unmanaged = .{}, + .allocator = allocator, + .ctx = ctx, + }; + } + + /// Release the backing array and invalidate this map. + /// This does *not* deinit keys, values, or the context! + /// If your keys or values need to be released, ensure + /// that that is done before calling this function. + pub fn deinit(self: *Self) void { + self.unmanaged.deinit(self.allocator); + self.* = undefined; + } + + /// Empty the map, but keep the backing allocation for future use. + /// This does *not* free keys or values! Be sure to + /// release them if they need deinitialization before + /// calling this function. + pub fn clearRetainingCapacity(self: *Self) void { + return self.unmanaged.clearRetainingCapacity(); + } + + /// Empty the map and release the backing allocation. + /// This does *not* free keys or values! Be sure to + /// release them if they need deinitialization before + /// calling this function. + pub fn clearAndFree(self: *Self) void { + return self.unmanaged.clearAndFree(self.allocator); + } + + /// Return the number of items in the map. + pub fn count(self: Self) Size { + return self.unmanaged.count(); + } + + /// Create an iterator over the entries in the map. + /// The iterator is invalidated if the map is modified. + pub fn iterator(self: *const Self) Iterator { + return self.unmanaged.iterator(); + } + + /// If key exists this function cannot fail. + /// If there is an existing item with `key`, then the result + /// `Entry` pointers point to it, and found_existing is true. + /// Otherwise, puts a new item with undefined value, and + /// the `Entry` pointers point to it. Caller should then initialize + /// the value (but not the key). + pub fn getOrPut(self: *Self, key: K) !GetOrPutResult { + return self.unmanaged.getOrPutContext(self.allocator, key, self.ctx); + } + + /// If key exists this function cannot fail. + /// If there is an existing item with `key`, then the result + /// `Entry` pointers point to it, and found_existing is true. + /// Otherwise, puts a new item with undefined key and value, and + /// the `Entry` pointers point to it. Caller must then initialize + /// the key and value. + pub fn getOrPutAdapted(self: *Self, key: anytype, ctx: anytype) !GetOrPutResult { + return self.unmanaged.getOrPutContextAdapted(self.allocator, key, ctx, self.ctx); + } + + /// If there is an existing item with `key`, then the result + /// `Entry` pointers point to it, and found_existing is true. + /// Otherwise, puts a new item with undefined value, and + /// the `Entry` pointers point to it. Caller should then initialize + /// the value (but not the key). + /// If a new entry needs to be stored, this function asserts there + /// is enough capacity to store it. + pub fn getOrPutAssumeCapacity(self: *Self, key: K) GetOrPutResult { + return self.unmanaged.getOrPutAssumeCapacityContext(key, self.ctx); + } + + /// If there is an existing item with `key`, then the result + /// `Entry` pointers point to it, and found_existing is true. + /// Otherwise, puts a new item with undefined value, and + /// the `Entry` pointers point to it. Caller must then initialize + /// the key and value. + /// If a new entry needs to be stored, this function asserts there + /// is enough capacity to store it. + pub fn getOrPutAssumeCapacityAdapted(self: *Self, key: anytype, ctx: anytype) GetOrPutResult { + return self.unmanaged.getOrPutAssumeCapacityAdapted(self.allocator, key, ctx); + } + + pub fn getOrPutValue(self: *Self, key: K, value: V) !Entry { + return self.unmanaged.getOrPutValueContext(self.allocator, key, value, self.ctx); + } + + /// Increases capacity, guaranteeing that insertions up until the + /// `expected_count` will not cause an allocation, and therefore cannot fail. + pub fn ensureCapacity(self: *Self, expected_count: Size) !void { + return self.unmanaged.ensureCapacityContext(self.allocator, expected_count, self.ctx); + } + + /// Returns the number of total elements which may be present before it is + /// no longer guaranteed that no allocations will be performed. + pub fn capacity(self: *Self) Size { + return self.unmanaged.capacity(); + } + + /// Clobbers any existing data. To detect if a put would clobber + /// existing data, see `getOrPut`. + pub fn put(self: *Self, key: K, value: V) !void { + return self.unmanaged.putContext(self.allocator, key, value, self.ctx); + } + + /// Inserts a key-value pair into the hash map, asserting that no previous + /// entry with the same key is already present + pub fn putNoClobber(self: *Self, key: K, value: V) !void { + return self.unmanaged.putNoClobberContext(self.allocator, key, value, self.ctx); + } + + /// Asserts there is enough capacity to store the new key-value pair. + /// Clobbers any existing data. To detect if a put would clobber + /// existing data, see `getOrPutAssumeCapacity`. + pub fn putAssumeCapacity(self: *Self, key: K, value: V) void { + return self.unmanaged.putAssumeCapacityContext(key, value, self.ctx); + } + + /// Asserts there is enough capacity to store the new key-value pair. + /// Asserts that it does not clobber any existing data. + /// To detect if a put would clobber existing data, see `getOrPutAssumeCapacity`. + pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void { + return self.unmanaged.putAssumeCapacityNoClobberContext(key, value, self.ctx); + } + + /// Inserts a new `Entry` into the hash map, returning the previous one, if any. + pub fn fetchPut(self: *Self, key: K, value: V) !?KV { + return self.unmanaged.fetchPutContext(self.allocator, key, value, self.ctx); + } + + /// Inserts a new `Entry` into the hash map, returning the previous one, if any. + /// If insertion happuns, asserts there is enough capacity without allocating. + pub fn fetchPutAssumeCapacity(self: *Self, key: K, value: V) ?KV { + return self.unmanaged.fetchPutAssumeCapacityContext(key, value, self.ctx); + } + + /// Removes a value from the map and returns the removed kv pair. + pub fn fetchRemove(self: *Self, key: K) ?KV { + return self.unmanaged.fetchRemoveContext(key, self.ctx); + } + + pub fn fetchRemoveAdapted(self: *Self, key: anytype, ctx: anytype) ?KV { + return self.unmanaged.fetchRemoveAdapted(key, ctx); + } + + /// Finds the value associated with a key in the map + pub fn get(self: Self, key: K) ?*V { + return self.unmanaged.getContext(key, self.ctx); + } + + pub fn getAdapted(self: Self, key: anytype, ctx: anytype) ?*V { + return self.unmanaged.getAdapted(key, ctx); + } + + /// Finds the key and value associated with a key in the map + pub fn getEntry(self: Self, key: K) ?Entry { + return self.unmanaged.getEntryContext(key, self.ctx); + } + + pub fn getEntryAdapted(self: Self, key: anytype, ctx: anytype) ?Entry { + return self.unmanaged.getEntryAdapted(key, ctx); + } + + /// Check if the map contains a key + pub fn contains(self: Self, key: K) bool { + return self.unmanaged.containsContext(key, self.ctx); + } + + pub fn containsAdapted(self: Self, key: anytype, ctx: anytype) bool { + return self.unmanaged.containsAdapted(key, ctx); + } + + /// If there is an `Entry` with a matching key, it is deleted from + /// the hash map, and then returned from this function. + pub fn remove(self: *Self, key: K) bool { + return self.unmanaged.removeContext(key, self.ctx); + } + + pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool { + return self.unmanaged.removeAdapted(key, ctx); + } + + /// Creates a copy of this map, using the same allocator + pub fn clone(self: Self) !Self { + var other = try self.unmanaged.cloneContext(self.allocator, self.ctx); + return other.promoteContext(self.allocator, self.ctx); + } + + /// Creates a copy of this map, using a specified allocator + pub fn cloneWithAllocator(self: Self, new_allocator: *Allocator) !Self { + var other = try self.unmanaged.cloneContext(new_allocator, self.ctx); + return other.promoteContext(new_allocator, self.ctx); + } + + /// Creates a copy of this map, using a specified context + pub fn cloneWithContext(self: Self, new_ctx: anytype) !HashMap(K, V, @TypeOf(new_ctx), max_load_percentage) { + var other = try self.unmanaged.cloneContext(self.allocator, new_ctx); + return other.promoteContext(self.allocator, new_ctx); + } + + /// Creates a copy of this map, using a specified allocator and context + pub fn cloneWithAllocatorAndContext(new_allocator: *Allocator, new_ctx: anytype) !HashMap(K, V, @TypeOf(new_ctx), max_load_percentage) { + var other = try self.unmanaged.cloneContext(new_allocator, new_ctx); + return other.promoteContext(new_allocator, new_ctx); + } + }; +} + +/// A HashMap based on open addressing and linear probing. +/// A lookup or modification typically occurs only 2 cache misses. +/// No order is guaranteed and any modification invalidates live iterators. +/// It achieves good performance with quite high load factors (by default, +/// grow is triggered at 80% full) and only one byte of overhead per element. +/// The struct itself is only 16 bytes for a small footprint. This comes at +/// the price of handling size with u32, which should be reasonnable enough +/// for almost all uses. +/// Deletions are achieved with tombstones. +pub fn HashMapUnmanaged( + comptime K: type, + comptime V: type, + comptime Context: type, + comptime max_load_percentage: u64, +) type { + if (max_load_percentage <= 0 or max_load_percentage >= 100) + @compileError("max_load_percentage must be between 0 and 100."); + comptime verifyContext(Context, K, K, u64); + + return struct { + const Self = @This(); + + // This is actually a midway pointer to the single buffer containing + // a `Header` field, the `Metadata`s and `Entry`s. + // At `-@sizeOf(Header)` is the Header field. + // At `sizeOf(Metadata) * capacity + offset`, which is pointed to by + // self.header().entries, is the array of entries. + // This means that the hashmap only holds one live allocation, to + // reduce memory fragmentation and struct size. + /// Pointer to the metadata. + metadata: ?[*]Metadata = null, + + /// Current number of elements in the hashmap. + size: Size = 0, + + // Having a countdown to grow reduces the number of instructions to + // execute when determining if the hashmap has enough capacity already. + /// Number of available slots before a grow is needed to satisfy the + /// `max_load_percentage`. + available: Size = 0, + + // This is purely empirical and not a /very smart magic constant™/. + /// Capacity of the first grow when bootstrapping the hashmap. + const minimal_capacity = 8; + + // This hashmap is specially designed for sizes that fit in a u32. + pub const Size = u32; + + // u64 hashes guarantee us that the fingerprint bits will never be used + // to compute the index of a slot, maximizing the use of entropy. + pub const Hash = u64; + + pub const Entry = struct { + key: *K, + value: *V, + }; + + pub const KV = struct { + key: K, + value: V, + }; + + const Header = packed struct { + values: [*]V, + keys: [*]K, + capacity: Size, + }; + + /// Metadata for a slot. It can be in three states: empty, used or + /// tombstone. Tombstones indicate that an entry was previously used, + /// they are a simple way to handle removal. + /// To this state, we add 6 bits from the slot's key hash. These are + /// used as a fast way to disambiguate between entries without + /// having to use the equality function. If two fingerprints are + /// different, we know that we don't have to compare the keys at all. + /// The 6 bits are the highest ones from a 64 bit hash. This way, not + /// only we use the `log2(capacity)` lowest bits from the hash to determine + /// a slot index, but we use 6 more bits to quickly resolve collisions + /// when multiple elements with different hashes end up wanting to be in / the same slot. + /// Not using the equality function means we don't have to read into + /// the entries array, avoiding a likely cache miss. + const Metadata = packed struct { + const FingerPrint = u6; + + used: u1 = 0, + tombstone: u1 = 0, + fingerprint: FingerPrint = 0, + + pub fn isUsed(self: Metadata) bool { + return self.used == 1; + } + + pub fn isTombstone(self: Metadata) bool { + return self.tombstone == 1; + } + + pub fn takeFingerprint(hash: Hash) FingerPrint { + const hash_bits = @typeInfo(Hash).Int.bits; + const fp_bits = @typeInfo(FingerPrint).Int.bits; + return @truncate(FingerPrint, hash >> (hash_bits - fp_bits)); + } + + pub fn fill(self: *Metadata, fp: FingerPrint) void { + self.used = 1; + self.tombstone = 0; + self.fingerprint = fp; + } + + pub fn remove(self: *Metadata) void { + self.used = 0; + self.tombstone = 1; + self.fingerprint = 0; + } + }; + + comptime { + assert(@sizeOf(Metadata) == 1); + assert(@alignOf(Metadata) == 1); + } + + pub const Iterator = struct { + hm: *const Self, + index: Size = 0, + + pub fn next(it: *Iterator) ?Entry { + assert(it.index <= it.hm.capacity()); + if (it.hm.size == 0) return null; + + const cap = it.hm.capacity(); + const end = it.hm.metadata.? + cap; + var metadata = it.hm.metadata.? + it.index; + + while (metadata != end) : ({ + metadata += 1; + it.index += 1; + }) { + if (metadata[0].isUsed()) { + const key = &it.hm.keys()[it.index]; + const value = &it.hm.values()[it.index]; + it.index += 1; + return Entry{ .key = key, .value = value }; + } + } + + return null; + } + }; + + pub const GetOrPutResult = struct { + entry: Entry, + found_existing: bool, + }; + + pub const Managed = HashMap(K, V, Context, max_load_percentage); + + pub fn promote(self: Self, allocator: *Allocator) Managed { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call promoteContext instead."); + return promoteContext(self, allocator, undefined); + } + + pub fn promoteContext(self: Self, allocator: *Allocator, ctx: Context) Managed { + return .{ + .unmanaged = self, + .allocator = allocator, + .ctx = ctx, + }; + } + + fn isUnderMaxLoadPercentage(size: Size, cap: Size) bool { + return size * 100 < max_load_percentage * cap; + } + + pub fn deinit(self: *Self, allocator: *Allocator) void { + self.deallocate(allocator); + self.* = undefined; + } + + fn capacityForSize(size: Size) Size { + var new_cap = @truncate(u32, (@as(u64, size) * 100) / max_load_percentage + 1); + new_cap = math.ceilPowerOfTwo(u32, new_cap) catch unreachable; + return new_cap; + } + + pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_size: Size) !void { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call ensureCapacityContext instead."); + return ensureCapacityContext(self, allocator, new_size, undefined); + } + + pub fn ensureCapacityContext(self: *Self, allocator: *Allocator, new_size: Size, ctx: Context) !void { + if (new_size > self.size) + try self.growIfNeeded(allocator, new_size - self.size, ctx); + } + + pub fn clearRetainingCapacity(self: *Self) void { + if (self.metadata) |_| { + self.initMetadatas(); + self.size = 0; + self.available = @truncate(u32, (self.capacity() * max_load_percentage) / 100); + } + } + + pub fn clearAndFree(self: *Self, allocator: *Allocator) void { + self.deallocate(allocator); + self.size = 0; + self.available = 0; + } + + pub fn count(self: *const Self) Size { + return self.size; + } + + fn header(self: *const Self) *Header { + return @ptrCast(*Header, @ptrCast([*]Header, self.metadata.?) - 1); + } + + fn keys(self: *const Self) [*]K { + return self.header().keys; + } + + fn values(self: *const Self) [*]V { + return self.header().values; + } + + pub fn capacity(self: *const Self) Size { + if (self.metadata == null) return 0; + + return self.header().capacity; + } + + pub fn iterator(self: *const Self) Iterator { + return .{ .hm = self }; + } + + pub fn putNoClobber(self: *Self, allocator: *Allocator, key: K, value: V) !void { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putNoClobberContext instead."); + return self.putNoClobberContext(allocator, key, value, undefined); + } + + /// Insert an entry in the map. Assumes it is not already present. + pub fn putNoClobberContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !void { + assert(!self.containsContext(key, ctx)); + try self.growIfNeeded(allocator, 1, ctx); + + self.putAssumeCapacityNoClobberContext(key, value, ctx); + } + + /// Asserts there is enough capacity to store the new key-value pair. + /// Clobbers any existing data. To detect if a put would clobber + /// existing data, see `getOrPutAssumeCapacity`. + pub fn putAssumeCapacity(self: *Self, key: K, value: V) void { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putAssumeCapacityContext instead."); + return self.putAssumeCapacityContext(key, value, undefined); + } + + pub fn putAssumeCapacityContext(self: *Self, key: K, value: V, ctx: Context) void { + const gop = self.getOrPutAssumeCapacityContext(key, ctx); + gop.entry.value.* = value; + } + + pub fn putAssumeCapacityNoClobber(self: *Self, key: K, value: V) void { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putAssumeCapacityNoClobberContext instead."); + return self.putAssumeCapacityNoClobberContext(key, value, undefined); + } + + /// Insert an entry in the map. Assumes it is not already present, + /// and that no allocation is needed. + pub fn putAssumeCapacityNoClobberContext(self: *Self, key: K, value: V, ctx: Context) void { + assert(!self.containsContext(key, ctx)); + + const hash = ctx.hash(key); + const mask = self.capacity() - 1; + var idx = @truncate(usize, hash & mask); + + var metadata = self.metadata.? + idx; + while (metadata[0].isUsed()) { + idx = (idx + 1) & mask; + metadata = self.metadata.? + idx; + } + + if (!metadata[0].isTombstone()) { + assert(self.available > 0); + self.available -= 1; + } + + const fingerprint = Metadata.takeFingerprint(hash); + metadata[0].fill(fingerprint); + self.keys()[idx] = key; + self.values()[idx] = value; + + self.size += 1; + } + + /// Inserts a new `Entry` into the hash map, returning the previous one, if any. + pub fn fetchPut(self: *Self, allocator: *Allocator, key: K, value: V) !?KV { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutContext instead."); + return self.fetchPutContext(allocator, key, value, undefined); + } + + pub fn fetchPutContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !?KV { + const gop = try self.getOrPutContext(allocator, key, ctx); + var result: ?KV = null; + if (gop.found_existing) { + result = KV{ + .key = gop.entry.key.*, + .value = gop.entry.value.*, + }; + } + gop.entry.value.* = value; + return result; + } + + /// Inserts a new `Entry` into the hash map, returning the previous one, if any. + /// If insertion happens, asserts there is enough capacity without allocating. + pub fn fetchPutAssumeCapacity(self: *Self, key: K, value: V) ?KV { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchPutAssumeCapacityContext instead."); + return self.fetchPutAssumeCapacityContext(allocator, key, value, undefined); + } + + pub fn fetchPutAssumeCapacityContext(self: *Self, key: K, value: V, ctx: Context) ?KV { + const gop = self.getOrPutAssumeCapacityContext(key, ctx); + var result: ?KV = null; + if (gop.found_existing) { + result = KV{ + .key = gop.entry.key.*, + .value = gop.entry.value.*, + }; + } + gop.entry.value.* = value; + return result; + } + + /// If there is an `Entry` with a matching key, it is deleted from + /// the hash map, and then returned from this function. + pub fn fetchRemove(self: *Self, key: K) ?KV { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call fetchRemoveContext instead."); + return self.fetchRemoveContext(allocator, key, value, undefined); + } + + pub fn fetchRemoveContext(self: *Self, key: K, ctx: Context) ?KV { + return self.fetchRemoveAdapted(key, ctx); + } + + pub fn fetchRemoveAdapted(self: *Self, key: anytype, ctx: anytype) ?KV { + if (self.getIndex(key, ctx)) |idx| { + const old_key = &self.keys()[idx]; + const old_val = &self.values()[idx]; + const result = KV{ + .key = old_key.*, + .value = old_val.*, + }; + self.metadata.?[idx].remove(); + old_key.* = undefined; + old_val.* = undefined; + self.size -= 1; + return result; + } + + return null; + } + + /// Find the index containing the data for the given key. + /// Whether this function returns null is almost always + /// branched on after this function returns, and this function + /// returns null/not null from separate code paths. We + /// want the optimizer to remove that branch and instead directly + /// fuse the basic blocks after the branch to the basic blocks + /// from this function. To encourage that, this function is + /// marked as inline. + fn getIndex(self: Self, key: anytype, ctx: anytype) callconv(.Inline) ?usize { + comptime verifyContext(@TypeOf(ctx), @TypeOf(key), K, Hash); + + if (self.size == 0) { + return null; + } + + // If you get a compile error on this line, it means that your generic hash + // function is invalid for these parameters. + const hash = ctx.hash(key); + // verifyContext can't verify the return type of generic hash functions, + // so we need to double-check it here. + if (@TypeOf(hash) != Hash) { + @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic hash function that returns the wrong type! " ++ @typeName(Hash) ++ " was expected, but found " ++ @typeName(@TypeOf(hash))); + } + const mask = self.capacity() - 1; + const fingerprint = Metadata.takeFingerprint(hash); + var idx = @truncate(usize, hash & mask); + + var metadata = self.metadata.? + idx; + while (metadata[0].isUsed() or metadata[0].isTombstone()) { + if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { + const test_key = &self.keys()[idx]; + // If you get a compile error on this line, it means that your generic eql + // function is invalid for these parameters. + const eql = ctx.eql(key, test_key.*); + // verifyContext can't verify the return type of generic eql functions, + // so we need to double-check it here. + if (@TypeOf(eql) != bool) { + @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic eql function that returns the wrong type! bool was expected, but found " ++ @typeName(@TypeOf(eql))); + } + if (eql) { + return idx; + } + } + + idx = (idx + 1) & mask; + metadata = self.metadata.? + idx; + } + + return null; + } + + pub fn getEntry(self: Self, key: K) ?Entry { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getEntryContext instead."); + return self.getEntryContext(key, undefined); + } + + pub fn getEntryContext(self: Self, key: K, ctx: Context) ?Entry { + return self.getEntryAdapted(key, ctx); + } + + pub fn getEntryAdapted(self: Self, key: anytype, ctx: anytype) ?Entry { + if (self.getIndex(key, ctx)) |idx| { + return Entry{ + .key = &self.keys()[idx], + .value = &self.values()[idx], + }; + } + return null; + } + + /// Insert an entry if the associated key is not already present, otherwise update preexisting value. + pub fn put(self: *Self, allocator: *Allocator, key: K, v: Value) !void { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call putContext instead."); + return self.putContext(allocator, key, value, undefined); + } + + pub fn putContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !void { + const result = try self.getOrPutContext(allocator, key, ctx); + result.entry.value.* = value; + } + + /// Get an optional pointer to the value associated with key, if present. + pub fn get(self: Self, key: K, ctx: Context) ?*V { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getContext instead."); + return self.getContext(key, undefined); + } + + pub fn getContext(self: Self, key: K, ctx: Context) ?*V { + return self.getAdapted(key, ctx); + } + + /// Get an optional pointer to the value associated with key, if present. + pub fn getAdapted(self: Self, key: anytype, ctx: anytype) ?*V { + if (self.getIndex(key, ctx)) |idx| { + return &self.values()[idx]; + } + return null; + } + + pub fn getOrPut(self: *Self, allocator: *Allocator, key: K) !GetOrPutResult { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContext instead."); + return self.getOrPutContext(allocator, key, undefined); + } + + pub fn getOrPutContext(self: *Self, allocator: *Allocator, key: K, ctx: Context) !GetOrPutResult { + const gop = try self.getOrPutContextAdapted(allocator, key, ctx, ctx); + if (!gop.found_existing) { + gop.entry.key.* = key; + } + return gop; + } + + pub fn getOrPutAdapted(self: *Self, allocator: *Allocator, key: anytype, key_ctx: anytype) !GetOrPutResult { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutContextAdapted instead."); + return self.getOrPutContextAdapted(allocator, key, key_ctx, undefined); + } + + pub fn getOrPutContextAdapted(self: *Self, allocator: *Allocator, key: anytype, key_ctx: anytype, ctx: Context) !GetOrPutResult { + self.growIfNeeded(allocator, 1, ctx) catch |err| { + // If allocation fails, try to do the lookup anyway. + // If we find an existing item, we can return it. + // Otherwise return the error, we could not add another. + const index = self.getIndex(key, key_ctx) orelse return err; + return GetOrPutResult{ + .entry = .{ + .key = &self.keys()[index], + .value = &self.values()[index], + }, + .found_existing = true, + }; + }; + return self.getOrPutAssumeCapacityAdapted(key, key_ctx); + } + + pub fn getOrPutAssumeCapacity(self: *Self, key: K) GetOrPutResult { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutAssumeCapacityContext instead."); + return self.getOrPutAssumeCapacityContext(key, undefined); + } + + pub fn getOrPutAssumeCapacityContext(self: *Self, key: K, ctx: Context) GetOrPutResult { + const result = self.getOrPutAssumeCapacityAdapted(key, ctx); + if (!result.found_existing) { + result.entry.key.* = key; + } + return result; + } + + pub fn getOrPutAssumeCapacityAdapted(self: *Self, key: anytype, ctx: anytype) GetOrPutResult { + comptime verifyContext(@TypeOf(ctx), @TypeOf(key), K, Hash); + + // If you get a compile error on this line, it means that your generic hash + // function is invalid for these parameters. + const hash = ctx.hash(key); + // verifyContext can't verify the return type of generic hash functions, + // so we need to double-check it here. + if (@TypeOf(hash) != Hash) { + @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic hash function that returns the wrong type! " ++ @typeName(Hash) ++ " was expected, but found " ++ @typeName(@TypeOf(hash))); + } + const mask = self.capacity() - 1; + const fingerprint = Metadata.takeFingerprint(hash); + var idx = @truncate(usize, hash & mask); + + var first_tombstone_idx: usize = self.capacity(); // invalid index + var metadata = self.metadata.? + idx; + while (metadata[0].isUsed() or metadata[0].isTombstone()) { + if (metadata[0].isUsed() and metadata[0].fingerprint == fingerprint) { + const test_key = &self.keys()[idx]; + // If you get a compile error on this line, it means that your generic eql + // function is invalid for these parameters. + const eql = ctx.eql(key, test_key.*); + // verifyContext can't verify the return type of generic eql functions, + // so we need to double-check it here. + if (@TypeOf(eql) != bool) { + @compileError("Context " ++ @typeName(@TypeOf(ctx)) ++ " has a generic eql function that returns the wrong type! bool was expected, but found " ++ @typeName(@TypeOf(eql))); + } + if (eql) { + return GetOrPutResult{ .entry = .{ + .key = test_key, + .value = &self.values()[idx], + }, .found_existing = true }; + } + } else if (first_tombstone_idx == self.capacity() and metadata[0].isTombstone()) { + first_tombstone_idx = idx; + } + + idx = (idx + 1) & mask; + metadata = self.metadata.? + idx; + } + + if (first_tombstone_idx < self.capacity()) { + // Cheap try to lower probing lengths after deletions. Recycle a tombstone. + idx = first_tombstone_idx; + metadata = self.metadata.? + idx; + } else { + // We're using a slot previously free. + self.available -= 1; + } + + metadata[0].fill(fingerprint); + const new_key = &self.keys()[idx]; + const new_value = &self.values()[idx]; + new_key.* = key; + new_value.* = undefined; + self.size += 1; + + return GetOrPutResult{ .entry = .{ + .key = new_key, + .value = new_value, + }, .found_existing = false }; + } + + pub fn getOrPutValue(self: *Self, allocator: *Allocator, key: K, value: V) !Entry { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call getOrPutValueContext instead."); + return self.getOrPutValueContext(allocator, key, value, undefined); + } + + pub fn getOrPutValueContext(self: *Self, allocator: *Allocator, key: K, value: V, ctx: Context) !Entry { + const res = try self.getOrPutAdapted(allocator, key, ctx); + if (!res.found_existing) { + res.entry.key.* = key; + res.entry.value.* = value; + } + return res.entry; + } + + /// Return true if there is a value associated with key in the map. + pub fn contains(self: *const Self, key: K) bool { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call containsContext instead."); + return self.containsContext(key, undefined); + } + + pub fn containsContext(self: *const Self, key: K, ctx: Context) bool { + return self.containsAdapted(key, ctx); + } + + pub fn containsAdapted(self: *const Self, key: anytype, ctx: anytype) bool { + return self.getIndex(key, ctx) != null; + } + + /// If there is an `Entry` with a matching key, it is deleted from + /// the hash map, and this function returns true. Otherwise this + /// function returns false. + pub fn remove(self: *Self, key: K) bool { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call removeContext instead."); + return self.removeContext(key, undefined); + } + + pub fn removeContext(self: *Self, key: K, ctx: Context) bool { + return self.removeAdapted(key, ctx); + } + + pub fn removeAdapted(self: *Self, key: anytype, ctx: anytype) bool { + if (self.getIndex(key, ctx)) |idx| { + self.metadata.?[idx].remove(); + self.keys()[idx] = undefined; + self.values()[idx] = undefined; + self.size -= 1; + return true; + } + + return false; + } + + fn initMetadatas(self: *Self) void { + @memset(@ptrCast([*]u8, self.metadata.?), 0, @sizeOf(Metadata) * self.capacity()); + } + + // This counts the number of occupied slots, used + tombstones, which is + // what has to stay under the max_load_percentage of capacity. + fn load(self: *const Self) Size { + const max_load = (self.capacity() * max_load_percentage) / 100; + assert(max_load >= self.available); + return @truncate(Size, max_load - self.available); + } + + fn growIfNeeded(self: *Self, allocator: *Allocator, new_count: Size, ctx: Context) !void { + if (new_count > self.available) { + try self.grow(allocator, capacityForSize(self.load() + new_count), ctx); + } + } + + pub fn clone(self: Self, allocator: *Allocator) !Self { + if (@sizeOf(Context) != 0) + @compileError("Cannot infer context " ++ @typeName(Context) ++ ", call cloneContext instead."); + return self.cloneContext(key, @as(Context, undefined)); + } + + pub fn cloneContext(self: Self, allocator: *Allocator, new_ctx: anytype) !HashMapUnmanaged(K, V, @TypeOf(new_ctx), max_load_percentage) { + var other = HashMapUnmanaged(K, V, @TypeOf(new_ctx), max_load_percentage){}; + if (self.size == 0) + return other; + + const new_cap = capacityForSize(self.size); + try other.allocate(allocator, new_cap); + other.initMetadatas(); + other.available = @truncate(u32, (new_cap * max_load_percentage) / 100); + + var i: Size = 0; + var metadata = self.metadata.?; + var keys_ptr = self.keys(); + var values_ptr = self.values(); + while (i < self.capacity()) : (i += 1) { + if (metadata[i].isUsed()) { + other.putAssumeCapacityNoClobberContext(keys_ptr[i], values_ptr[i], new_ctx); + if (other.size == self.size) + break; + } + } + + return other; + } + + fn grow(self: *Self, allocator: *Allocator, new_capacity: Size, ctx: Context) !void { + @setCold(true); + const new_cap = std.math.max(new_capacity, minimal_capacity); + assert(new_cap > self.capacity()); + assert(std.math.isPowerOfTwo(new_cap)); + + var map = Self{}; + defer map.deinit(allocator); + try map.allocate(allocator, new_cap); + map.initMetadatas(); + map.available = @truncate(u32, (new_cap * max_load_percentage) / 100); + + if (self.size != 0) { + const old_capacity = self.capacity(); + var i: Size = 0; + var metadata = self.metadata.?; + var keys_ptr = self.keys(); + var values_ptr = self.values(); + while (i < old_capacity) : (i += 1) { + if (metadata[i].isUsed()) { + map.putAssumeCapacityNoClobberContext(keys_ptr[i], values_ptr[i], ctx); + if (map.size == self.size) + break; + } + } + } + + self.size = 0; + std.mem.swap(Self, self, &map); + } + + fn allocate(self: *Self, allocator: *Allocator, new_capacity: Size) !void { + const header_align = @alignOf(Header); + const key_align = if (@sizeOf(K) == 0) 1 else @alignOf(K); + const val_align = if (@sizeOf(V) == 0) 1 else @alignOf(V); + const max_align = comptime math_max3(header_align, key_align, val_align); + + const meta_size = @sizeOf(Header) + new_capacity * @sizeOf(Metadata); + comptime assert(@alignOf(Metadata) == 1); + + const keys_start = std.mem.alignForward(meta_size, key_align); + const keys_end = keys_start + new_capacity * @sizeOf(K); + + const vals_start = std.mem.alignForward(keys_end, val_align); + const vals_end = vals_start + new_capacity * @sizeOf(V); + + const total_size = std.mem.alignForward(vals_end, max_align); + + const slice = try allocator.alignedAlloc(u8, max_align, total_size); + const ptr = @ptrToInt(slice.ptr); + + const metadata = ptr + @sizeOf(Header); + + const hdr = @intToPtr(*Header, ptr); + if (@sizeOf([*]V) != 0) { + hdr.values = @intToPtr([*]V, ptr + vals_start); + } + if (@sizeOf([*]K) != 0) { + hdr.keys = @intToPtr([*]K, ptr + keys_start); + } + hdr.capacity = new_capacity; + self.metadata = @intToPtr([*]Metadata, metadata); + } + + fn deallocate(self: *Self, allocator: *Allocator) void { + if (self.metadata == null) return; + + const header_align = @alignOf(Header); + const key_align = if (@sizeOf(K) == 0) 1 else @alignOf(K); + const val_align = if (@sizeOf(V) == 0) 1 else @alignOf(V); + const max_align = comptime math_max3(header_align, key_align, val_align); + + const cap = self.capacity(); + const meta_size = @sizeOf(Header) + cap * @sizeOf(Metadata); + comptime assert(@alignOf(Metadata) == 1); + + const keys_start = std.mem.alignForward(meta_size, key_align); + const keys_end = keys_start + cap * @sizeOf(K); + + const vals_start = std.mem.alignForward(keys_end, val_align); + const vals_end = vals_start + cap * @sizeOf(V); + + const total_size = std.mem.alignForward(vals_end, max_align); + + const slice = @intToPtr([*]align(max_align) u8, @ptrToInt(self.header()))[0..total_size]; + allocator.free(slice); + + self.metadata = null; + self.available = 0; + } + }; +} + +const testing = std.testing; +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; + +test "std.hash_map basic usage" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + const count = 5; + var i: u32 = 0; + var total: u32 = 0; + while (i < count) : (i += 1) { + try map.put(i, i); + total += i; + } + + var sum: u32 = 0; + var it = map.iterator(); + while (it.next()) |kv| { + sum += kv.key.*; + } + try expectEqual(total, sum); + + i = 0; + sum = 0; + while (i < count) : (i += 1) { + try expectEqual(i, map.get(i).?.*); + sum += map.get(i).?.*; + } + try expectEqual(total, sum); +} + +test "std.hash_map ensureCapacity" { + var map = AutoHashMap(i32, i32).init(std.testing.allocator); + defer map.deinit(); + + try map.ensureCapacity(20); + const initial_capacity = map.capacity(); + try testing.expect(initial_capacity >= 20); + var i: i32 = 0; + while (i < 20) : (i += 1) { + try testing.expect(map.fetchPutAssumeCapacity(i, i + 10) == null); + } + // shouldn't resize from putAssumeCapacity + try testing.expect(initial_capacity == map.capacity()); +} + +test "std.hash_map ensureCapacity with tombstones" { + var map = AutoHashMap(i32, i32).init(std.testing.allocator); + defer map.deinit(); + + var i: i32 = 0; + while (i < 100) : (i += 1) { + try map.ensureCapacity(@intCast(u32, map.count() + 1)); + map.putAssumeCapacity(i, i); + // Remove to create tombstones that still count as load in the hashmap. + _ = map.remove(i); + } +} + +test "std.hash_map clearRetainingCapacity" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + map.clearRetainingCapacity(); + + try map.put(1, 1); + try expectEqual(map.get(1).?.*, 1); + try expectEqual(map.count(), 1); + + map.clearRetainingCapacity(); + map.putAssumeCapacity(1, 1); + try expectEqual(map.get(1).?.*, 1); + try expectEqual(map.count(), 1); + + const cap = map.capacity(); + try expect(cap > 0); + + map.clearRetainingCapacity(); + map.clearRetainingCapacity(); + try expectEqual(map.count(), 0); + try expectEqual(map.capacity(), cap); + try expect(!map.contains(1)); +} + +test "std.hash_map grow" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + const growTo = 12456; + + var i: u32 = 0; + while (i < growTo) : (i += 1) { + try map.put(i, i); + } + try expectEqual(map.count(), growTo); + + i = 0; + var it = map.iterator(); + while (it.next()) |kv| { + try expectEqual(kv.key.*, kv.value.*); + i += 1; + } + try expectEqual(i, growTo); + + i = 0; + while (i < growTo) : (i += 1) { + try expectEqual(map.get(i).?.*, i); + } +} + +test "std.hash_map clone" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var a = try map.clone(); + defer a.deinit(); + + try expectEqual(a.count(), 0); + + try a.put(1, 1); + try a.put(2, 2); + try a.put(3, 3); + + var b = try a.clone(); + defer b.deinit(); + + try expectEqual(b.count(), 3); + try expectEqual(b.get(1).?.*, 1); + try expectEqual(b.get(2).?.*, 2); + try expectEqual(b.get(3).?.*, 3); +} + +test "std.hash_map ensureCapacity with existing elements" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + try map.put(0, 0); + try expectEqual(map.count(), 1); + try expectEqual(map.capacity(), @TypeOf(map).Unmanaged.minimal_capacity); + + try map.ensureCapacity(65); + try expectEqual(map.count(), 1); + try expectEqual(map.capacity(), 128); +} + +test "std.hash_map ensureCapacity satisfies max load factor" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + try map.ensureCapacity(127); + try expectEqual(map.capacity(), 256); +} + +test "std.hash_map remove" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var i: u32 = 0; + while (i < 16) : (i += 1) { + try map.put(i, i); + } + + i = 0; + while (i < 16) : (i += 1) { + if (i % 3 == 0) { + _ = map.remove(i); + } + } + try expectEqual(map.count(), 10); + var it = map.iterator(); + while (it.next()) |kv| { + try expectEqual(kv.key.*, kv.value.*); + try expect(kv.key.* % 3 != 0); + } + + i = 0; + while (i < 16) : (i += 1) { + if (i % 3 == 0) { + try expect(!map.contains(i)); + } else { + try expectEqual(map.get(i).?.*, i); + } + } +} + +test "std.hash_map reverse removes" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var i: u32 = 0; + while (i < 16) : (i += 1) { + try map.putNoClobber(i, i); + } + + i = 16; + while (i > 0) : (i -= 1) { + _ = map.remove(i - 1); + try expect(!map.contains(i - 1)); + var j: u32 = 0; + while (j < i - 1) : (j += 1) { + try expectEqual(map.get(j).?.*, j); + } + } + + try expectEqual(map.count(), 0); +} + +test "std.hash_map multiple removes on same metadata" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var i: u32 = 0; + while (i < 16) : (i += 1) { + try map.put(i, i); + } + + _ = map.remove(7); + _ = map.remove(15); + _ = map.remove(14); + _ = map.remove(13); + try expect(!map.contains(7)); + try expect(!map.contains(15)); + try expect(!map.contains(14)); + try expect(!map.contains(13)); + + i = 0; + while (i < 13) : (i += 1) { + if (i == 7) { + try expect(!map.contains(i)); + } else { + try expectEqual(map.get(i).?.*, i); + } + } + + try map.put(15, 15); + try map.put(13, 13); + try map.put(14, 14); + try map.put(7, 7); + i = 0; + while (i < 16) : (i += 1) { + try expectEqual(map.get(i).?.*, i); + } +} + +test "std.hash_map put and remove loop in random order" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var keys = std.ArrayList(u32).init(std.testing.allocator); + defer keys.deinit(); + + const size = 32; + const iterations = 100; + + var i: u32 = 0; + while (i < size) : (i += 1) { + try keys.append(i); + } + var rng = std.rand.DefaultPrng.init(0); + + while (i < iterations) : (i += 1) { + std.rand.Random.shuffle(&rng.random, u32, keys.items); + + for (keys.items) |key| { + try map.put(key, key); + } + try expectEqual(map.count(), size); + + for (keys.items) |key| { + _ = map.remove(key); + } + try expectEqual(map.count(), 0); + } +} + +test "std.hash_map remove one million elements in random order" { + const Map = AutoHashMap(u32, u32); + const n = 1000 * 1000; + var map = Map.init(std.heap.page_allocator); + defer map.deinit(); + + var keys = std.ArrayList(u32).init(std.heap.page_allocator); + defer keys.deinit(); + + var i: u32 = 0; + while (i < n) : (i += 1) { + keys.append(i) catch unreachable; + } + + var rng = std.rand.DefaultPrng.init(0); + std.rand.Random.shuffle(&rng.random, u32, keys.items); + + for (keys.items) |key| { + map.put(key, key) catch unreachable; + } + + std.rand.Random.shuffle(&rng.random, u32, keys.items); + i = 0; + while (i < n) : (i += 1) { + const key = keys.items[i]; + _ = map.remove(key); + } +} + +test "std.hash_map put" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var i: u32 = 0; + while (i < 16) : (i += 1) { + try map.put(i, i); + } + + i = 0; + while (i < 16) : (i += 1) { + try expectEqual(map.get(i).?.*, i); + } + + i = 0; + while (i < 16) : (i += 1) { + try map.put(i, i * 16 + 1); + } + + i = 0; + while (i < 16) : (i += 1) { + try expectEqual(map.get(i).?.*, i * 16 + 1); + } +} + +test "std.hash_map putAssumeCapacity" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + try map.ensureCapacity(20); + var i: u32 = 0; + while (i < 20) : (i += 1) { + map.putAssumeCapacityNoClobber(i, i); + } + + i = 0; + var sum = i; + while (i < 20) : (i += 1) { + sum += map.get(i).?.*; + } + try expectEqual(sum, 190); + + i = 0; + while (i < 20) : (i += 1) { + map.putAssumeCapacity(i, 1); + } + + i = 0; + sum = i; + while (i < 20) : (i += 1) { + sum += map.get(i).?.*; + } + try expectEqual(sum, 20); +} + +test "std.hash_map getOrPut" { + var map = AutoHashMap(u32, u32).init(std.testing.allocator); + defer map.deinit(); + + var i: u32 = 0; + while (i < 10) : (i += 1) { + try map.put(i * 2, 2); + } + + i = 0; + while (i < 20) : (i += 1) { + var n = try map.getOrPutValue(i, 1); + } + + i = 0; + var sum = i; + while (i < 20) : (i += 1) { + sum += map.get(i).?.*; + } + + try expectEqual(sum, 30); +} + +test "std.hash_map basic hash map usage" { + var map = AutoHashMap(i32, i32).init(std.testing.allocator); + defer map.deinit(); + + try testing.expect((try map.fetchPut(1, 11)) == null); + try testing.expect((try map.fetchPut(2, 22)) == null); + try testing.expect((try map.fetchPut(3, 33)) == null); + try testing.expect((try map.fetchPut(4, 44)) == null); + + try map.putNoClobber(5, 55); + try testing.expect((try map.fetchPut(5, 66)).?.value == 55); + try testing.expect((try map.fetchPut(5, 55)).?.value == 66); + + const gop1 = try map.getOrPut(5); + try testing.expect(gop1.found_existing == true); + try testing.expect(gop1.entry.value.* == 55); + gop1.entry.value.* = 77; + try testing.expect(map.getEntry(5).?.value.* == 77); + + const gop2 = try map.getOrPut(99); + try testing.expect(gop2.found_existing == false); + gop2.entry.value.* = 42; + try testing.expect(map.getEntry(99).?.value.* == 42); + + const gop3 = try map.getOrPutValue(5, 5); + try testing.expect(gop3.value.* == 77); + + const gop4 = try map.getOrPutValue(100, 41); + try testing.expect(gop4.value.* == 41); + + try testing.expect(map.contains(2)); + try testing.expect(map.getEntry(2).?.value.* == 22); + try testing.expect(map.get(2).?.* == 22); + + const rmv1 = map.fetchRemove(2); + try testing.expect(rmv1.?.key == 2); + try testing.expect(rmv1.?.value == 22); + try testing.expect(map.fetchRemove(2) == null); + try testing.expect(map.remove(2) == false); + try testing.expect(map.getEntry(2) == null); + try testing.expect(map.get(2) == null); + + try testing.expect(map.remove(3) == true); +} + +test "std.hash_map clone" { + var original = AutoHashMap(i32, i32).init(std.testing.allocator); + defer original.deinit(); + + var i: u8 = 0; + while (i < 10) : (i += 1) { + try original.putNoClobber(i, i * 10); + } + + var copy = try original.clone(); + defer copy.deinit(); + + i = 0; + while (i < 10) : (i += 1) { + try testing.expect(copy.get(i).?.* == i * 10); + } +} diff --git a/src/js_ast.zig b/src/js_ast.zig index e3b1c62d5..ee6e35729 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -1455,10 +1455,10 @@ pub const Expr = struct { return Expr.joinWithComma(all[0], all[1], allocator); }, else => { - var expr = Expr.joinWithComma(all[0], all[1], allocator); - var _all = all[2 .. all.len - 1]; - for (_all) |right| { - expr = Expr.joinWithComma(expr, right, allocator); + var i: usize = 1; + var expr = all[0]; + while (i < all.len) : (i += 1) { + expr = Expr.joinWithComma(expr, all[i], allocator); } return expr; diff --git a/src/js_lexer.zig b/src/js_lexer.zig index ac575a062..89e2e06dd 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -2176,14 +2176,16 @@ fn float64(num: anytype) callconv(.Inline) f64 { } fn test_lexer(contents: []const u8) Lexer { - alloc.setup(std.heap.page_allocator) catch unreachable; + alloc.setup(std.heap.c_allocator) catch unreachable; var log = alloc.dynamic.create(logger.Log) catch unreachable; log.* = logger.Log.init(alloc.dynamic); - var source = logger.Source.initPathString( + var _source = logger.Source.initPathString( "index.js", contents, ); - return Lexer.init(log, &source, alloc.dynamic) catch unreachable; + var source = alloc.dynamic.create(logger.Source) catch unreachable; + source.* = _source; + return Lexer.init(log, source, alloc.dynamic) catch unreachable; } // test "LexerType.next()" { @@ -2238,7 +2240,7 @@ test "Lexer.next() simple" { try lex.next(); } -pub fn test_stringLiteralEquals(expected: string, source_text: string) void { +pub fn test_stringLiteralEquals(expected: string, source_text: string) !void { var msgs = std.ArrayList(logger.Msg).init(std.testing.allocator); var log = logger.Log{ .msgs = msgs, @@ -2256,8 +2258,9 @@ pub fn test_stringLiteralEquals(expected: string, source_text: string) void { try lex.next(); } - var lit = std.unicode.utf16leToUtf8Alloc(std.heap.page_allocator, lex.string_literal) catch unreachable; + var lit = std.unicode.utf16leToUtf8Alloc(std.heap.page_allocator, lex.stringLiteralUTF16()) catch unreachable; std.testing.expectEqualStrings(expected, lit); + std.testing.expectEqualStrings(expected, lex.string_literal_slice); } pub fn test_skipTo(lexer: *LexerType, n: string) void { @@ -2269,10 +2272,10 @@ pub fn test_skipTo(lexer: *LexerType, n: string) void { } test "LexerType.rawTemplateContents" { - test_stringLiteralEquals("hello!", "const a = 'hello!';"); - test_stringLiteralEquals("hello!hi", "const b = 'hello!hi';"); - test_stringLiteralEquals("hello!\n\nhi", "const b = `hello!\n\nhi`;"); + try test_stringLiteralEquals("hello!", "const a = 'hello!';"); + try test_stringLiteralEquals("hello!hi", "const b = 'hello!hi';"); + try test_stringLiteralEquals("hello!\n\nhi", "const b = `hello!\n\nhi`;"); // TODO: \r\n // test_stringLiteralEquals("hello!\nhi", "const b = `hello!\r\nhi`;"); - test_stringLiteralEquals("hello!", "const b = `hello!${\"hi\"}`"); + try test_stringLiteralEquals("hello!", "const b = `hello!${\"hi\"}`"); } diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index cb48f08e3..39860b42e 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -3,7 +3,7 @@ usingnamespace @import("imports.zig"); const TemplatePartTuple = std.meta.Tuple(&[_]type{ []E.TemplatePart, logger.Loc }); const ScopeOrderList = std.ArrayListUnmanaged(?ScopeOrder); -var panic_buffer = std.mem.zeros(32 * 1024); +var panic_buffer = std.mem.zeroes([32 * 1024]u8); var panic_stream = std.io.fixedBufferStream(&panic_buffer); pub fn ExpressionTransposer(comptime ctx: type, visitor: fn (ptr: *ctx, arg: Expr, state: anytype) Expr) type { @@ -1771,6 +1771,8 @@ pub const P = struct { // This is a general place to put lots of Expr objects expr_list: List(Expr), + scope_order_to_visit: []ScopeOrder = &([_]ScopeOrder{}), + const TransposeState = struct { is_await_target: bool = false, is_then_catch_target: bool = false, @@ -1827,7 +1829,7 @@ pub const P = struct { p.import_records_for_current_part.append(import_record_index) catch unreachable; p.ignoreUsage(p.require_ref); - return p.e(E.Require{ .import_record_index = import_record_index }, arg.loc); + return p.e(E.Require{ .import_record_index = Ref.toInt(import_record_index) }, arg.loc); }, else => {}, } @@ -1845,13 +1847,16 @@ pub const P = struct { }; pub fn s(p: *P, t: anytype, loc: logger.Loc) Stmt { + // Output.print("\nStmt: {s} - {d}\n", .{ @typeName(@TypeOf(t)), loc.start }); if (@typeInfo(@TypeOf(t)) == .Pointer) { return Stmt.init(t, loc); } else { return Stmt.alloc(p.allocator, t, loc); } } + pub fn e(p: *P, t: anytype, loc: logger.Loc) Expr { + // Output.print("\nExpr: {s} - {d}\n", .{ @typeName(@TypeOf(t)), loc.start }); if (@typeInfo(@TypeOf(t)) == .Pointer) { return Expr.init(t, loc); } else { @@ -2222,6 +2227,23 @@ pub const P = struct { } pub fn prepareForVisitPass(p: *P) !void { + { + var count: usize = 0; + for (p.scopes_in_order.items) |item| { + if (item != null) { + count += 1; + } + } + var i: usize = 0; + p.scope_order_to_visit = try p.allocator.alloc(ScopeOrder, p.scopes_in_order.items.len); + for (p.scopes_in_order.items) |item| { + if (item) |_item| { + p.scope_order_to_visit[i] = _item; + i += 1; + } + } + } + try p.pushScopeForVisitPass(js_ast.Scope.Kind.entry, locModuleScope); p.fn_or_arrow_data_visit.is_outside_fn_or_arrow = true; p.module_scope = p.current_scope; @@ -2266,20 +2288,18 @@ pub const P = struct { } pub fn nextScopeInOrderForVisitPass(p: *P) ScopeOrder { - while (p.scopes_in_order.items[p.scopes_in_order_visitor_index] == null) { - p.scopes_in_order_visitor_index += 1; - } - const scope_order = p.scopes_in_order.items[p.scopes_in_order_visitor_index].?; - p.scopes_in_order_visitor_index += 1; - return scope_order; + const head = p.scope_order_to_visit[0]; + p.scope_order_to_visit = p.scope_order_to_visit[1..p.scope_order_to_visit.len]; + return head; } pub fn pushScopeForVisitPass(p: *P, kind: js_ast.Scope.Kind, loc: logger.Loc) !void { - for (p.scopes_in_order.items[p.scopes_in_order_visitor_index..p.scopes_in_order.items.len]) |scope_order, i| { - if (scope_order) |ord| { - Output.print("Scope ({d}, {d})\n", .{ @enumToInt(ord.scope.kind), ord.loc.start }); - } - } + // Output.print("\n+Loc: {d}\n", .{loc.start}); + // for (p.scopes_in_order.items[p.scopes_in_order_visitor_index..p.scopes_in_order.items.len]) |scope_order, i| { + // if (scope_order) |ord| { + // Output.print("Scope ({d}, {d})\n", .{ @enumToInt(ord.scope.kind), ord.loc.start }); + // } + // } const order = p.nextScopeInOrderForVisitPass(); // Sanity-check that the scopes generated by the first and second passes match @@ -2296,7 +2316,6 @@ pub const P = struct { debugl("<pushScopeForParsePass>"); defer debugl("</pushScopeForParsePass>"); var parent: *Scope = p.current_scope; - p.scope_id += 1; var scope = try p.allocator.create(Scope); scope.* = Scope{ @@ -2308,7 +2327,6 @@ pub const P = struct { .kind = kind, .label_ref = null, .parent = parent, - .id = p.scope_id, }; try parent.children.append(scope); @@ -2351,7 +2369,7 @@ pub const P = struct { // Remember the length in case we call popAndDiscardScope() later const scope_index = p.scopes_in_order.items.len; try p.scopes_in_order.append(p.allocator, ScopeOrder{ .loc = loc, .scope = scope }); - + // Output.print("\nLoc: {d}\n", .{loc.start}); return scope_index; } @@ -3525,6 +3543,7 @@ pub const P = struct { } stmtOpts = ParseStatementOptions{}; try p.declareBinding(kind, value, &stmtOpts); + binding = value; } try p.lexer.expect(.t_open_brace); @@ -5008,23 +5027,27 @@ pub const P = struct { var name: ?js_ast.LocRef = null; _ = p.pushScopeForParsePass(.function_args, loc) catch unreachable; - defer p.popScope(); + // The name is optional if (p.lexer.token == .t_identifier) { - name = js_ast.LocRef{ - .loc = loc, + // Don't declare the name "arguments" since it's shadowed and inaccessible + var _name = js_ast.LocRef{ + .loc = p.lexer.loc(), .ref = null, }; - if (p.lexer.identifier.len > 0 and !strings.eql(p.lexer.identifier, "arguments")) { - (name orelse unreachable).ref = try p.declareSymbol(.hoisted_function, (name orelse unreachable).loc, p.lexer.identifier); + const text = p.lexer.identifier; + if (text.len > 0 and !strings.eql(text, "arguments")) { + _name.ref = try p.declareSymbol(.hoisted_function, _name.loc, text); } else { - (name orelse unreachable).ref = try p.newSymbol(.hoisted_function, p.lexer.identifier); + _name.ref = try p.newSymbol(.hoisted_function, text); } debug("FUNC NAME {s}", .{p.lexer.identifier}); + name = _name; try p.lexer.next(); } + // Even anonymous functions can have TypeScript type parameters if (p.options.ts) { p.skipTypescriptTypeParameters(); } @@ -5036,6 +5059,7 @@ pub const P = struct { }); p.validateFunctionName(func, .expr); + p.popScope(); return p.e(js_ast.E.Function{ .func = func, @@ -6281,6 +6305,7 @@ pub const P = struct { const yes = try p.parseExpr(.comma); p.allow_in = old_allow_in; + try p.lexer.expect(.t_colon); const no = try p.parseExpr(.comma); @@ -7069,6 +7094,7 @@ pub const P = struct { const class = try p.parseClass(classKeyword, name, ParseClassOptions{}); p.popScope(); + return p.e(class, loc); }, .t_new => { @@ -7906,9 +7932,7 @@ pub const P = struct { pub fn visitFunc(p: *P, func: *G.Fn, open_parens_loc: logger.Loc) void { const old_fn_or_arrow_data = p.fn_or_arrow_data_visit; - defer p.fn_or_arrow_data_visit = old_fn_or_arrow_data; const old_fn_only_data = p.fn_only_data_visit; - defer p.fn_only_data_visit = old_fn_only_data; p.fn_or_arrow_data_visit = FnOrArrowDataVisit{ .is_async = func.flags.is_async }; p.fn_only_data_visit = FnOnlyDataVisit{ .is_this_nested = true, .arguments_ref = func.arguments_ref }; @@ -7923,7 +7947,6 @@ pub const P = struct { } p.pushScopeForVisitPass(.function_args, open_parens_loc) catch unreachable; - defer p.popScope(); p.visitArgs( func.args, VisitArgsOpts{ @@ -7933,16 +7956,18 @@ pub const P = struct { }, ); - var body = func.body orelse p.panic("Expected visitFunc to have body {s}", .{func}); - p.pushScopeForVisitPass(.function_body, body.loc) catch unreachable; - defer p.popScope(); - var stmts = List(Stmt).fromOwnedSlice(p.allocator, body.stmts); - var temp_opts = PrependTempRefsOpts{ .kind = StmtsKind.fn_body, .fn_body_loc = body.loc }; + assert(func.body != null); + p.pushScopeForVisitPass(.function_body, func.body.?.loc) catch unreachable; + var stmts = List(Stmt).fromOwnedSlice(p.allocator, func.body.?.stmts); + var temp_opts = PrependTempRefsOpts{ .kind = StmtsKind.fn_body, .fn_body_loc = func.body.?.loc }; p.visitStmtsAndPrependTempRefs(&stmts, &temp_opts) catch unreachable; + func.body.?.stmts = stmts.toOwnedSlice(); - body.stmts = stmts.toOwnedSlice(); + p.popScope(); + p.popScope(); - func.body = body; + p.fn_or_arrow_data_visit = old_fn_or_arrow_data; + p.fn_only_data_visit = old_fn_only_data; } pub fn maybeKeepExprSymbolName(p: *P, expr: Expr, original_name: string, was_anonymous_named_expr: bool) Expr { @@ -7976,6 +8001,7 @@ pub const P = struct { } pub fn visitExprInOut(p: *P, expr: Expr, in: ExprIn) Expr { + // Output.print("\nVisit: {s} - {d}\n", .{ @tagName(expr.data), expr.loc.start }); switch (expr.data) { .e_null, .e_super, .e_boolean, .e_big_int, .e_reg_exp, .e_new_target, .e_undefined => {}, .e_string => |e_| { @@ -8713,7 +8739,10 @@ pub const P = struct { const side_effects = SideEffects.toBoolean(e_.test_.data); - if (side_effects.ok) { + if (!side_effects.ok) { + e_.yes = p.visitExpr(e_.yes); + e_.no = p.visitExpr(e_.no); + } else { // Mark the control flow as dead if the branch is never taken if (side_effects.value) { // "true ? live : dead" @@ -8730,9 +8759,6 @@ pub const P = struct { p.is_control_flow_dead = old; e_.no = p.visitExpr(e_.no); } - } else { - e_.yes = p.visitExpr(e_.yes); - e_.no = p.visitExpr(e_.no); } }, .e_await => |e_| { @@ -8788,68 +8814,68 @@ pub const P = struct { .e_object => |e_| { if (in.assign_target != .none) { p.maybeCommaSpreadError(e_.comma_after_spread); - var has_spread = false; - var has_proto = false; + } - var i: usize = 0; - while (i < e_.properties.len) : (i += 1) { - var property = e_.properties[i]; - - if (property.kind != .spread) { - const key = p.visitExpr(property.key orelse Global.panic("Expected property key", .{})); - e_.properties[i].key = key; - - // Forbid duplicate "__proto__" properties according to the specification - if (!property.flags.is_computed and !property.flags.was_shorthand and !property.flags.is_method and in.assign_target == .none and key.data.isStringValue() and strings.eqlComptime( - // __proto__ is utf8, assume it lives in refs - key.data.e_string.utf8, - "__proto__", - )) { - if (has_proto) { - const r = js_lexer.rangeOfIdentifier(p.source, key.loc); - p.log.addRangeError(p.source, r, "Cannot specify the \"__proto__\" property more than once per object") catch unreachable; - } - has_proto = true; - } - } else { - has_spread = true; - } + var has_spread = false; + var has_proto = false; + var i: usize = 0; + while (i < e_.properties.len) : (i += 1) { + var property = e_.properties[i]; - // Extract the initializer for expressions like "({ a: b = c } = d)" - if (in.assign_target != .none and property.initializer != null and property.value != null) { - switch (property.value.?.data) { - .e_binary => |bin| { - if (bin.op == .bin_assign) { - property.initializer = bin.right; - property.value = bin.left; - } - }, - else => {}, + if (property.kind != .spread) { + const key = p.visitExpr(property.key orelse Global.panic("Expected property key", .{})); + e_.properties[i].key = key; + + // Forbid duplicate "__proto__" properties according to the specification + if (!property.flags.is_computed and !property.flags.was_shorthand and !property.flags.is_method and in.assign_target == .none and key.data.isStringValue() and strings.eqlComptime( + // __proto__ is utf8, assume it lives in refs + key.data.e_string.utf8, + "__proto__", + )) { + if (has_proto) { + const r = js_lexer.rangeOfIdentifier(p.source, key.loc); + p.log.addRangeError(p.source, r, "Cannot specify the \"__proto__\" property more than once per object") catch unreachable; } + has_proto = true; } + } else { + has_spread = true; + } - if (property.value != null) { - property.value = p.visitExprInOut(property.value.?, ExprIn{ .assign_target = in.assign_target }); + // Extract the initializer for expressions like "({ a: b = c } = d)" + if (in.assign_target != .none and property.initializer != null and property.value != null) { + switch (property.value.?.data) { + .e_binary => |bin| { + if (bin.op == .bin_assign) { + property.initializer = bin.right; + property.value = bin.left; + } + }, + else => {}, } + } - if (property.initializer != null) { - const was_anonymous_named_expr = p.isAnonymousNamedExpr(property.initializer orelse unreachable); - property.initializer = p.visitExprInOut(property.initializer.?, ExprIn{ .assign_target = in.assign_target }); + if (property.value != null) { + property.value = p.visitExprInOut(property.value.?, ExprIn{ .assign_target = in.assign_target }); + } - if (property.value) |val| { - if (@as(Expr.Tag, val.data) == .e_identifier) { - property.initializer = p.maybeKeepExprSymbolName( - property.initializer orelse unreachable, - p.symbols.items[val.data.e_identifier.ref.inner_index].original_name, - was_anonymous_named_expr, - ); - } + if (property.initializer != null) { + const was_anonymous_named_expr = p.isAnonymousNamedExpr(property.initializer orelse unreachable); + property.initializer = p.visitExprInOut(property.initializer.?, ExprIn{ .assign_target = in.assign_target }); + + if (property.value) |val| { + if (@as(Expr.Tag, val.data) == .e_identifier) { + property.initializer = p.maybeKeepExprSymbolName( + property.initializer orelse unreachable, + p.symbols.items[val.data.e_identifier.ref.inner_index].original_name, + was_anonymous_named_expr, + ); } } - - // TODO: can we avoid htis copy - e_.properties[i] = property; } + + // TODO: can we avoid htis copy + e_.properties[i] = property; } }, .e_import => |e_| { @@ -8931,16 +8957,19 @@ pub const P = struct { p.fn_only_data_visit.is_inside_async_arrow_fn = e_.is_async or p.fn_only_data_visit.is_inside_async_arrow_fn; p.pushScopeForVisitPass(.function_args, expr.loc) catch unreachable; + var dupe = p.allocator.dupe(Stmt, e_.body.stmts) catch unreachable; + p.visitArgs(e_.args, VisitArgsOpts{ .has_rest_arg = e_.has_rest_arg, - .body = e_.body.stmts, + .body = dupe, .is_unique_formal_parameters = true, }); p.pushScopeForVisitPass(.function_body, e_.body.loc) catch unreachable; - var stmts_list = List(Stmt).fromOwnedSlice(p.allocator, e_.body.stmts); + var stmts_list = List(Stmt).fromOwnedSlice(p.allocator, dupe); var temp_opts = PrependTempRefsOpts{ .kind = StmtsKind.fn_body }; p.visitStmtsAndPrependTempRefs(&stmts_list, &temp_opts) catch unreachable; + p.allocator.free(e_.body.stmts); e_.body.stmts = stmts_list.toOwnedSlice(); p.popScope(); p.popScope(); @@ -9015,17 +9044,18 @@ pub const P = struct { } pub fn keepExprSymbolName(p: *P, _value: Expr, name: string) Expr { - var start = p.expr_list.items.len; - p.expr_list.ensureUnusedCapacity(2) catch unreachable; - p.expr_list.appendAssumeCapacity(_value); - p.expr_list.appendAssumeCapacity(p.e(E.String{ - .utf8 = name, - }, _value.loc)); + return _value; + // var start = p.expr_list.items.len; + // p.expr_list.ensureUnusedCapacity(2) catch unreachable; + // p.expr_list.appendAssumeCapacity(_value); + // p.expr_list.appendAssumeCapacity(p.e(E.String{ + // .utf8 = name, + // }, _value.loc)); - var value = p.callRuntime(_value.loc, "ℹ", p.expr_list.items[start..p.expr_list.items.len]); - // Make sure tree shaking removes this if the function is never used - value.data.e_call.can_be_unwrapped_if_unused = true; - return value; + // var value = p.callRuntime(_value.loc, "ℹ", p.expr_list.items[start..p.expr_list.items.len]); + // // Make sure tree shaking removes this if the function is never used + // value.data.e_call.can_be_unwrapped_if_unused = true; + // return value; } pub fn fnBodyContainsUseStrict(body: []Stmt) ?logger.Loc { @@ -9719,9 +9749,9 @@ pub const P = struct { .s_for => |data| { { p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; - defer p.popScope(); + if (data.init) |initst| { - _ = p.visitForLoopInit(initst, false); + data.init = p.visitForLoopInit(initst, false); } if (data.test_) |test_| { @@ -9735,6 +9765,7 @@ pub const P = struct { } data.body = p.visitLoopBody(data.body); + p.popScope(); } // TODO: Potentially relocate "var" declarations to the top level @@ -9782,32 +9813,36 @@ pub const P = struct { // p.lowerObjectRestInForLoopInit(s.Init, &s.Body) }, .s_try => |data| { + p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; { - p.pushScopeForVisitPass(.block, stmt.loc) catch unreachable; - defer p.popScope(); - p.fn_or_arrow_data_visit.try_body_count += 1; - defer p.fn_or_arrow_data_visit.try_body_count -= 1; var _stmts = List(Stmt).fromOwnedSlice(p.allocator, data.body); + p.fn_or_arrow_data_visit.try_body_count += 1; p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; + p.fn_or_arrow_data_visit.try_body_count -= 1; data.body = _stmts.toOwnedSlice(); } + p.popScope(); if (data.catch_) |*catch_| { p.pushScopeForVisitPass(.block, catch_.loc) catch unreachable; - defer p.popScope(); - if (catch_.binding != null and @as(Binding.Tag, catch_.binding.?.data) != .b_missing) { - p.visitBinding(catch_.binding.?, null); + { + if (catch_.binding != null) { + p.visitBinding(catch_.binding.?, null); + } + var _stmts = List(Stmt).fromOwnedSlice(p.allocator, catch_.body); + p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; + catch_.body = _stmts.toOwnedSlice(); } - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, data.body); - p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; - catch_.body = _stmts.toOwnedSlice(); + p.popScope(); } if (data.finally) |*finally| { p.pushScopeForVisitPass(.block, finally.loc) catch unreachable; - var _stmts = List(Stmt).fromOwnedSlice(p.allocator, data.body); - p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; - finally.stmts = _stmts.toOwnedSlice(); + { + var _stmts = List(Stmt).fromOwnedSlice(p.allocator, finally.stmts); + p.visitStmts(&_stmts, StmtsKind.none) catch unreachable; + finally.stmts = _stmts.toOwnedSlice(); + } p.popScope(); } }, @@ -10289,9 +10324,10 @@ pub const P = struct { pub fn visitLoopBody(p: *P, stmt: StmtNodeIndex) StmtNodeIndex { const old_is_inside_loop = p.fn_or_arrow_data_visit.is_inside_loop; p.fn_or_arrow_data_visit.is_inside_loop = true; - defer p.fn_or_arrow_data_visit.is_inside_loop = old_is_inside_loop; p.loop_body = stmt.data; - return p.visitSingleStmt(stmt, .loop_body); + const res = p.visitSingleStmt(stmt, .loop_body); + p.fn_or_arrow_data_visit.is_inside_loop = old_is_inside_loop; + return res; } pub fn visitSingleStmt(p: *P, stmt: Stmt, kind: StmtsKind) Stmt { @@ -10328,19 +10364,9 @@ pub const P = struct { return Stmt{ .data = Prefill.Data.SEmpty, .loc = loc }; } - if (stmts.len == 1) { - switch (stmts[0].data) { - .s_local => |local| { - // "let" and "const" must be put in a block when in a single-statement context - - if (local.kind == .k_var) { - return stmts[0]; - } - }, - else => { - return stmts[0]; - }, - } + if (stmts.len == 1 and std.meta.activeTag(stmts[0].data) != .s_local or (std.meta.activeTag(stmts[0].data) == .s_local and stmts[0].data.s_local.kind == S.Local.Kind.k_var)) { + // "let" and "const" must be put in a block when in a single-statement context + return stmts[0]; } return p.s(S.Block{ .stmts = stmts }, loc); @@ -10622,7 +10648,7 @@ pub const P = struct { // values that introduce new scopes and declare new symbols. If this is an // arrow function, then those new scopes will need to be parented under the // scope of the arrow function itself. - const scopeIndex = try p.pushScopeForParsePass(.function_args, loc); + const scope_index = try p.pushScopeForParsePass(.function_args, loc); // Allow "in" inside parentheses var oldAllowIn = p.allow_in; @@ -10754,12 +10780,12 @@ pub const P = struct { // If we get here, it's not an arrow function so undo the pushing of the // scope we did earlier. This needs to flatten any child scopes into the // parent scope as if the scope was never pushed in the first place. - p.popAndFlattenScope(scopeIndex); + p.popAndFlattenScope(scope_index); // If this isn't an arrow function, then types aren't allowed if (type_colon_range.len > 0) { try p.log.addRangeError(p.source, type_colon_range, "Unexpected \":\""); - p.panic("", .{}); + return error.ParseError; } // Are these arguments for a call to a function named "async"? @@ -10774,7 +10800,7 @@ pub const P = struct { p.logExprErrors(&errors); if (spread_range.len > 0) { try p.log.addRangeError(p.source, type_colon_range, "Unexpected \"...\""); - p.panic("", .{}); + return error.ParseError; } var value = Expr.joinAllWithComma(items, p.allocator); @@ -10784,7 +10810,7 @@ pub const P = struct { // Indicate that we expected an arrow function try p.lexer.expected(.t_equals_greater_than); - p.panic("", .{}); + return error.ParseError; } // This code is tricky. @@ -10793,6 +10819,7 @@ pub const P = struct { // The key is in how we remove scopes from the list // If we do an orderedRemove, it gets very slow. // swapRemove is fast. But a little more dangerous. + // Instead, we just tombstone it. pub fn popAndFlattenScope(p: *P, scope_index: usize) void { // Move up to the parent scope var to_flatten = p.current_scope; diff --git a/src/js_parser/js_parser_test.zig b/src/js_parser/js_parser_test.zig index 36252f715..0d76efc37 100644 --- a/src/js_parser/js_parser_test.zig +++ b/src/js_parser/js_parser_test.zig @@ -177,19 +177,21 @@ const SymbolList = [][]Symbol; fn expectPrinted(t: *Tester, contents: string, expected: string, src: anytype) !void { if (alloc.needs_setup) { - try alloc.setup(std.heap.page_allocator); + try alloc.setup(std.heap.c_allocator); + var __source = Output.Source.init(std.io.getStdOut(), std.io.getStdErr()); + + Output.Source.set(&__source); } debugl("INIT TEST"); - const opts = try options.TransformOptions.initUncached(alloc.dynamic, "file.jsx", contents); var log = logger.Log.init(alloc.dynamic); - var source = logger.Source.initFile(opts.entry_point, alloc.dynamic); + var source = logger.Source.initPathString("file.jsx", contents); var ast: js_ast.Ast = undefined; var define = try Define.init(alloc.dynamic, null); debugl("INIT PARSER"); - var parser = try Parser.init(opts, &log, &source, define, alloc.dynamic); + var parser = try Parser.init(Parser.Options{ .jsx = .{} }, &log, &source, define, alloc.dynamic); debugl("RUN PARSER"); var res = try parser.parse(); @@ -223,10 +225,10 @@ fn expectPrinted(t: *Tester, contents: string, expected: string, src: anytype) ! const PRINT_AST = false; test "expectPrint" { - var t_ = Tester.t(std.heap.page_allocator); + var t_ = Tester.t(std.heap.c_allocator); var t = &t_; // try expectPrinted(t, @embedFile("../test/fixtures/function-scope-bug.jsx"), @embedFile("../test/fixtures/function-scope-bug.jsx"), @src()); - try expectPrinted(t, @embedFile("../test/fixtures/simple.jsx"), @embedFile("../test/fixtures/simple.jsx"), @src()); + try expectPrinted(t, @embedFile("../test/fixtures/cannot-assign-to-import-bug.js"), @embedFile("../test/fixtures/cannot-assign-to-import-bug.js"), @src()); // try expectPrinted(t, "if (true) { console.log(\"hi\"); }", "if (true) { console.log(\"hi\"); }", @src()); // try expectPrinted(t, "try { console.log(\"hi\"); }\ncatch(er) { console.log('noooo'); }", "class Foo {\n foo() {\n }\n}\n", @src()); diff --git a/src/js_printer.zig b/src/js_printer.zig index f3b735688..a0142983f 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -1080,10 +1080,10 @@ pub fn NewPrinter(comptime ascii_only: bool) type { flags.forbid_in = true; p.printExpr(e.test_, .conditional, flags); p.printSpace(); - p.print("?"); + p.print("? "); p.printExpr(e.yes, .yield, ExprFlag.None()); p.printSpace(); - p.print(":"); + p.print(": "); flags.forbid_in = true; p.printExpr(e.no, .yield, flags); if (wrap) { diff --git a/src/json_parser.zig b/src/json_parser.zig index 120bcb4d7..ee28c2a93 100644 --- a/src/json_parser.zig +++ b/src/json_parser.zig @@ -249,7 +249,7 @@ const js_printer = @import("js_printer.zig"); const renamer = @import("renamer.zig"); const SymbolList = [][]Symbol; -fn expectPrintedJSON(_contents: string, expected: string) void { +fn expectPrintedJSON(_contents: string, expected: string) !void { var contents = alloc.dynamic.alloc(u8, _contents.len + 1) catch unreachable; std.mem.copy(u8, contents, _contents); contents[contents.len - 1] = ';'; @@ -292,20 +292,21 @@ fn expectPrintedJSON(_contents: string, expected: string) void { } test "ParseJSON" { - expectPrintedJSON("true", "true"); - expectPrintedJSON("false", "false"); - expectPrintedJSON("1", "1"); - expectPrintedJSON("10", "10"); - expectPrintedJSON("100", "100"); - expectPrintedJSON("100.1", "100.1"); - expectPrintedJSON("19.1", "19.1"); - expectPrintedJSON("19.12", "19.12"); - expectPrintedJSON("3.4159820837456", "3.4159820837456"); - expectPrintedJSON("-10000.25", "-10000.25"); - expectPrintedJSON("\"hi\"", "\"hi\""); - expectPrintedJSON("{\"hi\": 1, \"hey\": \"200\", \"boom\": {\"yo\": true}}", "({\"hi\": 1, \"hey\": \"200\", \"boom\": {\"yo\": true}})"); - expectPrintedJSON("{\"hi\": \"hey\"}", "({hi: \"hey\"})"); - expectPrintedJSON("{\"hi\": [\"hey\", \"yo\"]}", "({hi:[\"hey\",\"yo\"]})"); + try alloc.setup(std.heap.c_allocator); + try expectPrintedJSON("true", "true"); + try expectPrintedJSON("false", "false"); + try expectPrintedJSON("1", "1"); + try expectPrintedJSON("10", "10"); + try expectPrintedJSON("100", "100"); + try expectPrintedJSON("100.1", "100.1"); + try expectPrintedJSON("19.1", "19.1"); + try expectPrintedJSON("19.12", "19.12"); + try expectPrintedJSON("3.4159820837456", "3.4159820837456"); + try expectPrintedJSON("-10000.25", "-10000.25"); + try expectPrintedJSON("\"hi\"", "\"hi\""); + try expectPrintedJSON("{\"hi\": 1, \"hey\": \"200\", \"boom\": {\"yo\": true}}", "({\"hi\": 1, \"hey\": \"200\", \"boom\": {\"yo\": true}})"); + try expectPrintedJSON("{\"hi\": \"hey\"}", "({hi: \"hey\"})"); + try expectPrintedJSON("{\"hi\": [\"hey\", \"yo\"]}", "({hi:[\"hey\",\"yo\"]})"); // TODO: emoji? } diff --git a/src/logger.zig b/src/logger.zig index 98149cb5b..2584566eb 100644 --- a/src/logger.zig +++ b/src/logger.zig @@ -558,7 +558,7 @@ test "print msg" { } test "ErrorPosition" { - const source = Source{ .contents = @embedFile("./test/fixtures/simple.jsx"), .path = fs.Path.init("/src/test/fixtures/simple.jsx"), .identifier_name = "simple" }; + const source = Source.initPathString("/src/test/fixtures/simple.jsx", @embedFile("./test/fixtures/simple.jsx")); const error_position = source.initErrorPosition(Loc{ .start = 979 }); std.testing.expectEqual(@as(usize, 973), @as(usize, error_position.line_start)); diff --git a/src/options.zig b/src/options.zig index 4a2141a8a..6dd6ddbae 100644 --- a/src/options.zig +++ b/src/options.zig @@ -335,7 +335,7 @@ pub const BundleOptions = struct { } var resolved_defines = try defines.DefineData.from_input(user_defines, log, allocator); - + const output_dir_parts = [_]string{ try std.process.getCwdAlloc(allocator), transform.output_dir orelse "out" }; var opts: BundleOptions = BundleOptions{ .log = log, .resolve_mode = transform.resolve orelse .dev, @@ -343,6 +343,7 @@ pub const BundleOptions = struct { allocator, resolved_defines, ), + .output_dir = try std.fs.path.join(allocator, &output_dir_parts), .loaders = loaders, .write = transform.write orelse false, .external = ExternalModules.init(allocator, &fs.fs, fs.top_level_dir, transform.external, log), @@ -459,12 +460,3 @@ pub const TransformResult = struct { }; } }; - -test "TransformOptions.initUncached" { - try alloc.setup(std.heap.page_allocator); - const opts = try TransformOptions.initUncached(alloc.dynamic, "lol.jsx", "<Hi />"); - - std.testing.expectEqualStrings("lol", opts.entry_point.path.name.base); - std.testing.expectEqualStrings(".jsx", opts.entry_point.path.name.ext); - std.testing.expect(Loader.jsx == opts.loader); -} diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index afa190c4c..6304d032e 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -5,14 +5,72 @@ const options = @import("../options.zig"); const Fs = @import("../fs.zig"); const std = @import("std"); const cache = @import("../cache.zig"); - +const sync = @import("../sync.zig"); const TSConfigJSON = @import("./tsconfig_json.zig").TSConfigJSON; const PackageJSON = @import("./package_json.zig").PackageJSON; usingnamespace @import("./data_url.zig"); +const Wyhash = std.hash.Wyhash; +const hash_map_v2 = @import("../hash_map_v2.zig"); +const Mutex = sync.Mutex; const StringBoolMap = std.StringHashMap(bool); +// https://en.wikipedia.org/wiki/.bss#BSS_in_C +pub fn BSSSectionAllocator(comptime size: usize) type { + const FixedBufferAllocator = std.heap.FixedBufferAllocator; + return struct { + var backing_buf: [size]u8 = undefined; + var fixed_buffer_allocator = FixedBufferAllocator.init(&backing_buf); + var buf_allocator = &fixed_buffer_allocator.allocator; + const Allocator = std.mem.Allocator; + const Self = @This(); + + allocator: Allocator, + fallback_allocator: *Allocator, + + pub fn get(self: *Self) *Allocator { + return &self.allocator; + } + + pub fn init(fallback_allocator: *Allocator) Self { + return Self{ .fallback_allocator = fallback_allocator, .allocator = Allocator{ + .allocFn = BSSSectionAllocator(size).alloc, + .resizeFn = BSSSectionAllocator(size).resize, + } }; + } + + pub fn alloc( + allocator: *Allocator, + len: usize, + ptr_align: u29, + len_align: u29, + return_address: usize, + ) error{OutOfMemory}![]u8 { + const self = @fieldParentPtr(Self, "allocator", allocator); + return buf_allocator.allocFn(buf_allocator, len, ptr_align, len_align, return_address) catch + return self.fallback_allocator.allocFn(self.fallback_allocator, len, ptr_align, len_align, return_address); + } + + pub fn resize( + allocator: *Allocator, + buf: []u8, + buf_align: u29, + new_len: usize, + len_align: u29, + return_address: usize, + ) error{OutOfMemory}!usize { + const self = @fieldParentPtr(Self, "allocator", allocator); + if (fixed_buffer_allocator.ownsPtr(buf.ptr)) { + return fixed_buffer_allocator.allocator.resizeFn(&fixed_buffer_allocator.allocator, buf, buf_align, new_len, len_align, return_address); + } else { + return self.fallback_allocator.resizeFn(self.fallback_allocator, buf, buf_align, new_len, len_align, return_address); + } + } + }; +} + const Path = Fs.Path; + pub const SideEffectsData = struct { source: *logger.Source, range: logger.Range, @@ -22,21 +80,131 @@ pub const SideEffectsData = struct { }; pub const DirInfo = struct { + pub const Index = u32; + // These objects are immutable, so we can just point to the parent directory // and avoid having to lock the cache again - parent: ?*DirInfo = null, + parent: Index = HashMap.NotFound, // A pointer to the enclosing dirInfo with a valid "browser" field in // package.json. We need this to remap paths after they have been resolved. - enclosing_browser_scope: ?*DirInfo = null, + enclosing_browser_scope: Index = HashMap.NotFound, - abs_path: string, - entries: Fs.FileSystem.DirEntry, + abs_path: string = "", + entries: Fs.FileSystem.DirEntry = undefined, has_node_modules: bool = false, // Is there a "node_modules" subdirectory? package_json: ?*PackageJSON = null, // Is there a "package.json" file? tsconfig_json: ?*TSConfigJSON = null, // Is there a "tsconfig.json" file in this directory or a parent directory? abs_real_path: string = "", // If non-empty, this is the real absolute path resolving any symlinks + pub fn getParent(i: *DirInfo) ?*DirInfo { + if (i.parent == HashMap.NotFound) return null; + std.debug.assert(i.parent < HashMap.instance._data.len); + return &HashMap.instance._data.items(.value)[i.parent]; + } + pub fn getEnclosingBrowserScope(i: *DirInfo) ?*DirInfo { + if (i.enclosing_browser_scope == HashMap.NotFound) return null; + std.debug.assert(i.enclosing_browser_scope < HashMap.instance._data.len); + return &HashMap.instance._data.items(.value)[i.enclosing_browser_scope]; + } + + // Goal: Really fast, low allocation directory map exploiting cache locality where we don't worry about lifetimes much. + // 1. Don't store the keys or values of directories that don't exist + // 2. Don't expect a provided key to exist after it's queried + // 3. Store whether a directory has been queried and whether that query was successful. + // 4. Allocate onto the https://en.wikipedia.org/wiki/.bss#BSS_in_C instead of the heap, so we can avoid memory leaks + pub const HashMap = struct { + // In a small next.js app with few additional dependencies, there are 191 directories in the node_modules folder + // fd . -d 9999 -L -t d --no-ignore | wc -l + const PreallocatedCount = 256; + const StringAllocatorSize = 128 * PreallocatedCount; + const FallbackStringAllocator = BSSSectionAllocator(StringAllocatorSize); + const FallbackAllocatorSize = @divExact(@bitSizeOf(Entry), 8) * PreallocatedCount; + const FallbackAllocator = BSSSectionAllocator(FallbackAllocatorSize); + const BackingHashMap = std.AutoHashMapUnmanaged(u64, Index); + pub const Entry = struct { + key: string, + value: DirInfo, + }; + string_allocator: FallbackStringAllocator, + fallback_allocator: FallbackAllocator, + allocator: *std.mem.Allocator, + _data: std.MultiArrayList(Entry), + hash_map: BackingHashMap, + const Seed = 999; + pub const NotFound: Index = std.math.maxInt(Index); + var instance: HashMap = undefined; + + pub fn at(d: *HashMap, index: Index) *DirInfo { + return &d._data.items(.value)[index]; + } + + pub const Result = struct { + index: Index = NotFound, + hash: u64 = 0, + status: Status = Status.unknown, + + pub const Status = enum { unknown, not_found, exists }; + }; + + // pub fn get(d: *HashMap, key: string) Result { + // const _key = Wyhash.hash(Seed, key); + // const index = d.hash_map.get(_key) orelse return Result{}; + + // return d._data.items(.value)[index]; + // } + + pub fn getOrPut( + d: *HashMap, + key: string, + ) Result { + const _key = Wyhash.hash(Seed, key); + const index = d.hash_map.get(_key) orelse return Result{ + .index = std.math.maxInt(u32), + .status = .unknown, + .hash = _key, + }; + if (index == NotFound) { + return Result{ .index = NotFound, .status = .not_found, .hash = _key }; + } + + return Result{ .index = index, .status = .exists, .hash = _key }; + } + + pub fn put(d: *HashMap, hash: u64, key: string, value: DirInfo) *DirInfo { + const entry = Entry{ + .value = value, + .key = d.string_allocator.get().dupe(u8, key) catch unreachable, + }; + const index = d._data.len; + d._data.append(d.fallback_allocator.get(), entry) catch unreachable; + d.hash_map.put(d.allocator, hash, @intCast(DirInfo.Index, index)) catch unreachable; + return &d._data.items(.value)[index]; + } + + pub fn init(allocator: *std.mem.Allocator) *HashMap { + var list = std.MultiArrayList(Entry){}; + instance = HashMap{ + ._data = undefined, + .string_allocator = FallbackStringAllocator.init(allocator), + .allocator = allocator, + .hash_map = BackingHashMap{}, + .fallback_allocator = FallbackAllocator.init(allocator), + }; + list.ensureTotalCapacity(instance.allocator, PreallocatedCount) catch unreachable; + instance._data = list; + return &instance; + } + + pub fn markNotFound(d: *HashMap, hash: u64) void { + d.hash_map.put(d.allocator, hash, NotFound) catch unreachable; + } + + pub fn deinit(i: *HashMap) void { + i._data.deinit(i.allocator); + i.hash_map.deinit(i.allocator); + } + }; }; pub const TemporaryBuffer = struct { pub threadlocal var ExtensionPathBuf = std.mem.zeroes([512]u8); @@ -93,11 +261,11 @@ pub const Resolver = struct { // reducing parallelism in the resolver helps the rest of the bundler go // faster. I'm not sure why this is but please don't change this unless you // do a lot of testing with various benchmarks and there aren't any regressions. - mutex: std.Thread.Mutex, + mutex: Mutex, // This cache maps a directory path to information about that directory and // all parent directories - dir_cache: std.StringHashMap(?*DirInfo), + dir_cache: *DirInfo.HashMap, pub fn init1( allocator: *std.mem.Allocator, @@ -107,8 +275,8 @@ pub const Resolver = struct { ) Resolver { return Resolver{ .allocator = allocator, - .dir_cache = std.StringHashMap(?*DirInfo).init(allocator), - .mutex = std.Thread.Mutex{}, + .dir_cache = DirInfo.HashMap.init(allocator), + .mutex = Mutex.init(), .caches = cache.Cache.Set.init(allocator), .opts = opts, .fs = _fs, @@ -340,8 +508,8 @@ pub const Resolver = struct { return null; } - const hold = r.mutex.acquire(); - defer hold.release(); + r.mutex.lock(); + defer r.mutex.unlock(); var result = try r.resolveWithoutSymlinks(source_dir, import_path, kind); @@ -429,7 +597,7 @@ pub const Resolver = struct { // Check the "browser" map for the first time (1 out of 2) if (r.dirInfoCached(std.fs.path.dirname(abs_path) orelse unreachable) catch null) |_import_dir_info| { - if (_import_dir_info.enclosing_browser_scope) |import_dir_info| { + if (_import_dir_info.getEnclosingBrowserScope()) |import_dir_info| { if (import_dir_info.package_json) |pkg| { const pkg_json_dir = std.fs.path.dirname(pkg.source.key_path.text) orelse unreachable; @@ -491,7 +659,7 @@ pub const Resolver = struct { const source_dir_info = (r.dirInfoCached(source_dir) catch null) orelse return null; // Support remapping one package path to another via the "browser" field - if (source_dir_info.enclosing_browser_scope) |browser_scope| { + if (source_dir_info.getEnclosingBrowserScope()) |browser_scope| { if (browser_scope.package_json) |package_json| { if (r.checkBrowserMap(package_json, import_path)) |remapped| { if (remapped.len == 0) { @@ -533,7 +701,7 @@ pub const Resolver = struct { while (iter.next()) |*path| { const dirname = std.fs.path.dirname(path.text) orelse continue; const base_dir_info = ((r.dirInfoCached(dirname) catch null)) orelse continue; - const dir_info = base_dir_info.enclosing_browser_scope orelse continue; + const dir_info = base_dir_info.getEnclosingBrowserScope() orelse continue; const pkg_json = dir_info.package_json orelse continue; const rel_path = std.fs.path.relative(r.allocator, pkg_json.source.key_path.text, path.text) catch continue; if (r.checkBrowserMap(pkg_json, rel_path)) |remapped| { @@ -597,7 +765,7 @@ pub const Resolver = struct { if (r.loadAsFileOrDirectory(abs, kind)) |res| { return res; } - r.allocator.free(abs); + // r.allocator.free(abs); } } @@ -617,10 +785,10 @@ pub const Resolver = struct { if (r.loadAsFileOrDirectory(abs_path, kind)) |res| { return res; } - r.allocator.free(abs_path); + // r.allocator.free(abs_path); } - dir_info = dir_info.parent orelse break; + dir_info = dir_info.getParent() orelse break; } // Mostly to cut scope, we don't resolve `NODE_PATH` environment variable. @@ -720,11 +888,30 @@ pub const Resolver = struct { } fn dirInfoCached(r: *Resolver, path: string) !?*DirInfo { - const info = r.dir_cache.get(path) orelse try r.dirInfoUncached(path); + var dir_info_entry = r.dir_cache.getOrPut( + path, + ); + + switch (dir_info_entry.status) { + .unknown => { + return try r.dirInfoUncached(path, dir_info_entry); + }, + .not_found => { + return null; + }, + .exists => { + return r.dir_cache.at(dir_info_entry.index); + }, + } + // if (__entry.found_existing) { + // return if (__entry.entry.value == DirInfo.NotFound) null else __entry.entry.value; + // } - try r.dir_cache.put(path, info); + // __entry.entry.value = DirInfo.NotFound; - return info; + // try r.dirInfoUncached(path); + // const entry = r.dir_cache.get(path) orelse unreachable; + // return if (__entry.entry.value == DirInfo.NotFound) null else entry; } pub const MatchResult = struct { @@ -939,7 +1126,7 @@ pub const Resolver = struct { } // Potentially remap using the "browser" field - if (dir_info.enclosing_browser_scope) |browser_scope| { + if (dir_info.getEnclosingBrowserScope()) |browser_scope| { if (browser_scope.package_json) |browser_json| { if (r.checkBrowserMap(browser_json, field_rel_path)) |remap| { // Is the path disabled? @@ -1002,7 +1189,7 @@ pub const Resolver = struct { } pub fn loadAsIndexWithBrowserRemapping(r: *Resolver, dir_info: *DirInfo, path: string, extension_order: []const string) ?MatchResult { - if (dir_info.enclosing_browser_scope) |browser_scope| { + if (dir_info.getEnclosingBrowserScope()) |browser_scope| { comptime const field_rel_path = "index"; if (browser_scope.package_json) |browser_json| { if (r.checkBrowserMap(browser_json, field_rel_path)) |remap| { @@ -1280,12 +1467,23 @@ pub const Resolver = struct { return null; } - fn dirInfoUncached(r: *Resolver, path: string) anyerror!?*DirInfo { + fn dirInfoUncached(r: *Resolver, path: string, result: DirInfo.HashMap.Result) anyerror!?*DirInfo { var rfs: *Fs.FileSystem.RealFS = &r.fs.fs; var parent: ?*DirInfo = null; - const parent_dir = std.fs.path.dirname(path) orelse return null; - if (!strings.eql(parent_dir, path)) { - parent = try r.dirInfoCached(parent_dir); + + const parent_dir = std.fs.path.dirname(path) orelse { + r.dir_cache.markNotFound(result.hash); + return null; + }; + + var parent_result: DirInfo.HashMap.Result = undefined; + if (parent_dir.len > 1 and !strings.eql(parent_dir, path)) { + parent = (try r.dirInfoCached(parent_dir)) orelse { + r.dir_cache.markNotFound(result.hash); + return null; + }; + + parent_result = r.dir_cache.getOrPut(parent_dir); } // List the directories @@ -1323,6 +1521,7 @@ pub const Resolver = struct { @errorName(_entries.err.original_err), }, ) catch {}; + r.dir_cache.markNotFound(result.hash); return null; }, } @@ -1330,10 +1529,9 @@ pub const Resolver = struct { entries = _entries.entries; } - var info = try r.allocator.create(DirInfo); - info.* = DirInfo{ + var info = DirInfo{ .abs_path = path, - .parent = parent, + .parent = if (parent != null) parent_result.index else DirInfo.HashMap.NotFound, .entries = entries, }; @@ -1382,7 +1580,8 @@ pub const Resolver = struct { if (info.package_json) |pkg| { if (pkg.browser_map.count() > 0) { - info.enclosing_browser_scope = info; + // it has not been written yet, so we reserve the next index + info.enclosing_browser_scope = @intCast(DirInfo.Index, DirInfo.HashMap.instance._data.len); } if (r.debug_logs) |*logs| { @@ -1438,6 +1637,7 @@ pub const Resolver = struct { info.tsconfig_json = parent.?.tsconfig_json; } - return info; + info.entries = entries; + return r.dir_cache.put(result.hash, path, info); } }; diff --git a/src/test/fixtures/cannot-assign-to-import-bug.js b/src/test/fixtures/cannot-assign-to-import-bug.js new file mode 100644 index 000000000..cbf9087f1 --- /dev/null +++ b/src/test/fixtures/cannot-assign-to-import-bug.js @@ -0,0 +1,369 @@ +/** @license React v17.0.2 + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +"use strict"; +var l = require("object-assign"), + n = 60103, + p = 60106; +exports.Fragment = 60107; +exports.StrictMode = 60108; +exports.Profiler = 60114; +var q = 60109, + r = 60110, + t = 60112; +exports.Suspense = 60113; +var u = 60115, + v = 60116; +if ("function" === typeof Symbol && Symbol.for) { + var w = Symbol.for; + n = w("react.element"); + p = w("react.portal"); + exports.Fragment = w("react.fragment"); + exports.StrictMode = w("react.strict_mode"); + exports.Profiler = w("react.profiler"); + q = w("react.provider"); + r = w("react.context"); + t = w("react.forward_ref"); + exports.Suspense = w("react.suspense"); + u = w("react.memo"); + v = w("react.lazy"); +} +var x = "function" === typeof Symbol && Symbol.iterator; +function y(a) { + if (null === a || "object" !== typeof a) return null; + a = (x && a[x]) || a["@@iterator"]; + return "function" === typeof a ? a : null; +} +function z(a) { + for ( + var b = "https://reactjs.org/docs/error-decoder.html?invariant=" + a, c = 1; + c < arguments.length; + c++ + ) + b += "&args[]=" + encodeURIComponent(arguments[c]); + return ( + "Minified React error #" + + a + + "; visit " + + b + + " for the full message or use the non-minified dev environment for full errors and additional helpful warnings." + ); +} +var A = { + isMounted: function () { + return !1; + }, + enqueueForceUpdate: function () {}, + enqueueReplaceState: function () {}, + enqueueSetState: function () {}, + }, + B = {}; +function C(a, b, c) { + this.props = a; + this.context = b; + this.refs = B; + this.updater = c || A; +} +C.prototype.isReactComponent = {}; +C.prototype.setState = function (a, b) { + if ("object" !== typeof a && "function" !== typeof a && null != a) + throw Error(z(85)); + this.updater.enqueueSetState(this, a, b, "setState"); +}; +C.prototype.forceUpdate = function (a) { + this.updater.enqueueForceUpdate(this, a, "forceUpdate"); +}; +function D() {} +D.prototype = C.prototype; +function E(a, b, c) { + this.props = a; + this.context = b; + this.refs = B; + this.updater = c || A; +} +var F = (E.prototype = new D()); +F.constructor = E; +l(F, C.prototype); +F.isPureReactComponent = !0; +var G = { current: null }, + H = Object.prototype.hasOwnProperty, + I = { key: !0, ref: !0, __self: !0, __source: !0 }; +function J(a, b, c) { + var e, + d = {}, + k = null, + h = null; + if (null != b) + for (e in (void 0 !== b.ref && (h = b.ref), + void 0 !== b.key && (k = "" + b.key), + b)) + H.call(b, e) && !I.hasOwnProperty(e) && (d[e] = b[e]); + var g = arguments.length - 2; + if (1 === g) d.children = c; + else if (1 < g) { + for (var f = Array(g), m = 0; m < g; m++) f[m] = arguments[m + 2]; + d.children = f; + } + if (a && a.defaultProps) + for (e in ((g = a.defaultProps), g)) void 0 === d[e] && (d[e] = g[e]); + return { $$typeof: n, type: a, key: k, ref: h, props: d, _owner: G.current }; +} +function K(a, b) { + return { + $$typeof: n, + type: a.type, + key: b, + ref: a.ref, + props: a.props, + _owner: a._owner, + }; +} +function L(a) { + return "object" === typeof a && null !== a && a.$$typeof === n; +} +function escape(a) { + var b = { "=": "=0", ":": "=2" }; + return ( + "$" + + a.replace(/[=:]/g, function (a) { + return b[a]; + }) + ); +} +var M = /\/+/g; +function N(a, b) { + return "object" === typeof a && null !== a && null != a.key + ? escape("" + a.key) + : b.toString(36); +} +function O(a, b, c, e, d) { + var k = typeof a; + if ("undefined" === k || "boolean" === k) a = null; + var h = !1; + if (null === a) h = !0; + else + switch (k) { + case "string": + case "number": + h = !0; + break; + case "object": + switch (a.$$typeof) { + case n: + case p: + h = !0; + } + } + if (h) + return ( + (h = a), + (d = d(h)), + (a = "" === e ? "." + N(h, 0) : e), + Array.isArray(d) + ? ((c = ""), + null != a && (c = a.replace(M, "$&/") + "/"), + O(d, b, c, "", function (a) { + return a; + })) + : null != d && + (L(d) && + (d = K( + d, + c + + (!d.key || (h && h.key === d.key) + ? "" + : ("" + d.key).replace(M, "$&/") + "/") + + a + )), + b.push(d)), + 1 + ); + h = 0; + e = "" === e ? "." : e + ":"; + if (Array.isArray(a)) + for (var g = 0; g < a.length; g++) { + k = a[g]; + var f = e + N(k, g); + h += O(k, b, c, f, d); + } + else if (((f = y(a)), "function" === typeof f)) + for (a = f.call(a), g = 0; !(k = a.next()).done; ) + (k = k.value), (f = e + N(k, g++)), (h += O(k, b, c, f, d)); + else if ("object" === k) + throw ( + ((b = "" + a), + Error( + z( + 31, + "[object Object]" === b + ? "object with keys {" + Object.keys(a).join(", ") + "}" + : b + ) + )) + ); + return h; +} +function P(a, b, c) { + if (null == a) return a; + var e = [], + d = 0; + O(a, e, "", "", function (a) { + return b.call(c, a, d++); + }); + return e; +} +function Q(a) { + if (-1 === a._status) { + var b = a._result; + b = b(); + a._status = 0; + a._result = b; + b.then( + function (b) { + 0 === a._status && ((b = b.default), (a._status = 1), (a._result = b)); + }, + function (b) { + 0 === a._status && ((a._status = 2), (a._result = b)); + } + ); + } + if (1 === a._status) return a._result; + throw a._result; +} +var R = { current: null }; +function S() { + var a = R.current; + if (null === a) throw Error(z(321)); + return a; +} +var T = { + ReactCurrentDispatcher: R, + ReactCurrentBatchConfig: { transition: 0 }, + ReactCurrentOwner: G, + IsSomeRendererActing: { current: !1 }, + assign: l, +}; +exports.Children = { + map: P, + forEach: function (a, b, c) { + P( + a, + function () { + b.apply(this, arguments); + }, + c + ); + }, + count: function (a) { + var b = 0; + P(a, function () { + b++; + }); + return b; + }, + toArray: function (a) { + return ( + P(a, function (a) { + return a; + }) || [] + ); + }, + only: function (a) { + if (!L(a)) throw Error(z(143)); + return a; + }, +}; +exports.Component = C; +exports.PureComponent = E; +exports.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = T; +exports.cloneElement = function (a, b, c) { + if (null === a || void 0 === a) throw Error(z(267, a)); + var e = l({}, a.props), + d = a.key, + k = a.ref, + h = a._owner; + if (null != b) { + void 0 !== b.ref && ((k = b.ref), (h = G.current)); + void 0 !== b.key && (d = "" + b.key); + if (a.type && a.type.defaultProps) var g = a.type.defaultProps; + for (f in b) + H.call(b, f) && + !I.hasOwnProperty(f) && + (e[f] = void 0 === b[f] && void 0 !== g ? g[f] : b[f]); + } + var f = arguments.length - 2; + if (1 === f) e.children = c; + else if (1 < f) { + g = Array(f); + for (var m = 0; m < f; m++) g[m] = arguments[m + 2]; + e.children = g; + } + return { $$typeof: n, type: a.type, key: d, ref: k, props: e, _owner: h }; +}; +exports.createContext = function (a, b) { + void 0 === b && (b = null); + a = { + $$typeof: r, + _calculateChangedBits: b, + _currentValue: a, + _currentValue2: a, + _threadCount: 0, + Provider: null, + Consumer: null, + }; + a.Provider = { $$typeof: q, _context: a }; + return (a.Consumer = a); +}; +exports.createElement = J; +exports.createFactory = function (a) { + var b = J.bind(null, a); + b.type = a; + return b; +}; +exports.createRef = function () { + return { current: null }; +}; +exports.forwardRef = function (a) { + return { $$typeof: t, render: a }; +}; +exports.isValidElement = L; +exports.lazy = function (a) { + return { $$typeof: v, _payload: { _status: -1, _result: a }, _init: Q }; +}; +exports.memo = function (a, b) { + return { $$typeof: u, type: a, compare: void 0 === b ? null : b }; +}; +exports.useCallback = function (a, b) { + return S().useCallback(a, b); +}; +exports.useContext = function (a, b) { + return S().useContext(a, b); +}; +exports.useDebugValue = function () {}; +exports.useEffect = function (a, b) { + return S().useEffect(a, b); +}; +exports.useImperativeHandle = function (a, b, c) { + return S().useImperativeHandle(a, b, c); +}; +exports.useLayoutEffect = function (a, b) { + return S().useLayoutEffect(a, b); +}; +exports.useMemo = function (a, b) { + return S().useMemo(a, b); +}; +exports.useReducer = function (a, b, c) { + return S().useReducer(a, b, c); +}; +exports.useRef = function (a) { + return S().useRef(a); +}; +exports.useState = function (a) { + return S().useState(a); +}; +exports.version = "17.0.2"; diff --git a/src/test/fixtures/img-bug.js b/src/test/fixtures/img-bug.js index 1d5ec8a82..89b6d464d 100644 --- a/src/test/fixtures/img-bug.js +++ b/src/test/fixtures/img-bug.js @@ -1,48 +1,59 @@ -const hi = () => ({ - its_ireelevant: () => true, -}); -const hey = () => ({ - any_name_will_do: () => true, -}); - -// function getWidths(width, layout, sizes) { -// if (sizes && (layout === "fill" || layout === "responsive")) { -// // Find all the "vw" percent sizes used in the sizes prop -// const percentSizes = [...sizes.matchAll(/(^|\s)(1?\d?\d)vw/g)].map((m) => -// parseInt(m[2]) -// ); -// if (percentSizes.length) { - -// // const smallestRatio = Math.min(...percentSizes) * 0.01; -// // return { -// // widths: allSizes.filter( -// // (s) => s >= configDeviceSizes[0] * smallestRatio -// // ), -// // kind: "w", -// // }; -// } -// return { widths: allSizes, kind: "w" }; -// } -// if ( -// typeof width !== "number" || -// layout === "fill" || -// layout === "responsive" -// ) { -// return { widths: configDeviceSizes, kind: "w" }; -// } -// // const widths = [ -// // ...new Set( // > This means that most OLED screens that say they are 3x resolution, -// // // > are actually 3x in the green color, but only 1.5x in the red and -// // // > blue colors. Showing a 3x resolution image in the app vs a 2x -// // // > resolution image will be visually the same, though the 3x image -// // // > takes significantly more data. Even true 3x resolution screens are -// // // > wasteful as the human eye cannot see that level of detail without -// // // > something like a magnifying glass. -// // // https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html -// // [width, width * 2 /*, width * 3*/].map( -// // (w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1] -// // ) -// // ), -// // ]; -// // return { widths, kind: "x" }; +function hey() { + const well = { + baz: function () {}, + }; +} + +function yo() { + const hi = { + yo: function () {}, + }; +} + +// function yo() { +// const hi = { +// yo: function () {}, +// }; // } + +// This bug is the same as function-scope-bug.jsx, except this time, +// it's specific to scopes created in property definitions +// That means, either arrow functions or non-arrow functions + +// ESBUILD +// Scope: (5 -1) | Scope (5, -100) +// Scope: (6 12) | Scope (6, 12) +// Scope: (7 15) | Scope (7, 15) +// Scope: (6 43) | Scope (6, 43) +// Scope: (7 55) | Scope (7, 55) +// Scope: (6 78) | Scope (6, 78) +// Scope: (7 81) | Scope (7, 81) + +// Scope (6, 106) +// Scope (7, 118) + +// Scope: (5 -1) | Scope (5, -100) +// Scope: (6 12) | Scope (6, 12) +// Scope: (7 15) | Scope (7, 15) +// Scope: (6 43) | Scope (6, 43) +// Scope: (7 55) | Scope (7, 55) +// Scope: (6 78) | Scope (6, 78) +// Scope: (7 81) | Scope (7, 81) +// Scope: (6 106) | Scope (6, 106) +// Scope: (7 118) | Scope (7, 118) + +// ESBUILD + +// Scope: (5 -1) +// Scope: (6 12) +// Scope: (7 15) +// Scope: (6 43) +// Scope: (7 55) +// Scope: (6 78) +// Scope: (7 81) +// Scope: (6 106) +// Scope: (7 118) +// Scope: (6 141) +// Scope: (7 144) +// Scope: (6 169) +// Scope: (7 181) diff --git a/src/test/fixtures/react-dev-crash.js b/src/test/fixtures/react-dev-crash.js new file mode 100644 index 000000000..1bed979a5 --- /dev/null +++ b/src/test/fixtures/react-dev-crash.js @@ -0,0 +1,108 @@ +try { + // This should throw. + if (construct) { + // Something should be setting the props in the constructor. + var Fake = function () { + throw Error(); + }; // $FlowFixMe + + Object.defineProperty(Fake.prototype, "props", { + set: function () { + // We use a throwing setter instead of frozen or non-writable props + // because that won't throw in a non-strict mode function. + throw Error(); + }, + }); + + if (typeof Reflect === "object" && Reflect.construct) { + // We construct a different control for this case to include any extra + // frames added by the construct call. + try { + Reflect.construct(Fake, []); + } catch (x) { + control = x; + } + + Reflect.construct(fn, [], Fake); + } else { + try { + Fake.call(); + } catch (x) { + control = x; + } + + fn.call(Fake.prototype); + } + } else { + try { + throw Error(); + } catch (x) { + control = x; + } + + fn(); + } +} catch (sample) { + // This is inlined manually because closure doesn't do it for us. + if (sample && control && typeof sample.stack === "string") { + // This extracts the first frame from the sample that isn't also in the control. + // Skipping one frame that we assume is the frame that calls the two. + var sampleLines = sample.stack.split("\n"); + var controlLines = control.stack.split("\n"); + var s = sampleLines.length - 1; + var c = controlLines.length - 1; + + while (s >= 1 && c >= 0 && sampleLines[s] !== controlLines[c]) { + // We expect at least one stack frame to be shared. + // Typically this will be the root most one. However, stack frames may be + // cut off due to maximum stack limits. In this case, one maybe cut off + // earlier than the other. We assume that the sample is longer or the same + // and there for cut off earlier. So we should find the root most frame in + // the sample somewhere in the control. + c--; + } + + for (; s >= 1 && c >= 0; s--, c--) { + // Next we find the first one that isn't the same which should be the + // frame that called our sample function and the control. + if (sampleLines[s] !== controlLines[c]) { + // In V8, the first line is describing the message but other VMs don't. + // If we're about to return the first line, and the control is also on the same + // line, that's a pretty good indicator that our sample threw at same line as + // the control. I.e. before we entered the sample frame. So we ignore this result. + // This can happen if you passed a class to function component, or non-function. + if (s !== 1 || c !== 1) { + do { + s--; + c--; // We may still have similar intermediate frames from the construct call. + // The next one that isn't the same should be our match though. + + if (c < 0 || sampleLines[s] !== controlLines[c]) { + // V8 adds a "new" prefix for native classes. Let's remove it to make it prettier. + var _frame = "\n" + sampleLines[s].replace(" at new ", " at "); + + { + if (typeof fn === "function") { + componentFrameCache.set(fn, _frame); + } + } // Return the line we found. + + return _frame; + } + } while (s >= 1 && c >= 0); + } + + break; + } + } + } +} finally { + reentry = false; + + { + ReactCurrentDispatcher$1.current = previousDispatcher; + reenableLogs(); + } + + Error.prepareStackTrace = previousPrepareStackTrace; +} // Fallback to just using the name if we couldn't make it throw. |